Summary of Analysis
In this analysis, we investigate the impact of removing specific cell
types from the reference dataset and mapping/querying them using the
modified reference. The main steps include:
Cell Type Removal: CD4, CD8, CD14, and NK cell types are
systematically removed from the reference dataset.
Mapping and Querying: Utilizing the modified reference, we map the
query dataset.
Principal Component Regression: Regression of principal components
(PCs) against predicted cell types is performed. We visualize PC scatter
plots and box plots.
Distance Calculation: Calculation of Euclidean distances between the
cell types in the reference and the corresponding cell types in the
query.
Inter-Cell Type Distances: Computation of distances between the cell
types removed from the reference and the cell types to which they were
assigned in the query.
Introduction
Welcome to this document, where we delve into the results of a
regression analysis involving Principal Components (PCs) and cell
labels. Our exploration encompasses two distinct scenarios:
Regression of PCs against Observed Cell Labels in Query Dataset: This
scenario involves the regression of Principal Components against the
actual cell labels within the query dataset.
Regression of PCs against Predicted Cell Labels in Query Dataset: In
this scenario, we perform regression of Principal Components against
predicted cell labels in the query dataset. These predicted labels are
derived from systematically excluding one cell at a time from the
reference dataset. The modified reference is then employed to map the
query dataset.
The analysis hinges on a Single-Cell RNA sequencing (scRNA-seq) 10x
Genomics PBMC dataset. This dataset is divided into two subsets: the
reference set (10x Single-Cell RNAseq PBMCs - Reference) and the query
dataset (10x Single-Cell RNAseq PBMCs - Withheld Test Set). The dataset
can be accessed from the following link: https://figshare.com/projects/Curated_10X_Data/137892
library(SingleR)
library(scater)
library(Polychrome)
library(plotly)
library(ggplot2)
Data Processing
In this section, we load the reference and withheld datasets,
log-transform the data, and explore the impact of removing different
cell types from the reference dataset on prediction accuracy.
Analysis - Removing Cell Types
Here, we analyze the effect of removing individual cell types from
the reference dataset on prediction accuracy using the SingleR package.
We have a reference dataset containing CD4, CD8, CD14, and NK cell
types. We remove CD4 cells from the reference and map query using this
reference. Similarly, this process is performed for CD8, CD14, and NK
cells individually, each time removing one cell type and mapping query
with this modified reference.
# Removal of one cell type at a time from reference
tab <- lapply(unique(reference$label), function(i) {
indx <- which(reference$label == i)
refn <- reference[, -indx]
annotations <- SingleR(query, ref = refn, labels = refn$label)
table_result <- as.data.frame(table(annotations$labels, query$label))
return(list(annotations = annotations, table_result = table_result))
})
df <- mapply(function(tbl_result, label) {
indx <- which(tbl_result$Var2 == label)
tbl_result[indx, ]
}, lapply(tab, `[[`, "table_result"), unique(reference$label), SIMPLIFY = FALSE)
df = do.call(rbind, df)
df <- subset(df, Freq > 0)
# Concordance plot
df$Var2 <- factor(df$Var2, levels = c("CD8", "NK", "CD4", "CD14"))
ggplot(df, aes(x = Var1, y = Var2, size = Freq)) +
geom_point() +
xlab("Predicted labels") +
ylab("Removed labels") +
theme_bw() +
theme(axis.text.x = element_text(angle = 45, hjust = 1))

The scatter plot above displays removed cell types from reference on
y axis and predicted cell type on x axis. For instance, if from
reference dataset CD8 cells are removed, It will be predicted as CD4
cells in a query dataset.
PCA and Regression analysis
In this section, we apply PCA to the query dataset and perform
regression analysis to understand the relationship between principal
components and observed cell labels from query dataset.
query <- runPCA(query)
# Function to regress PCs against cell labels
regress_PCs <- function(data) {
# Calculate R-squared values
lm_models <- lapply(1:10, function(i) {
lm_model <- lm(paste0("PC", i, " ~ CellTypes"), data = data)
return(lm_model)
})
# Calculate R-squared values
rsquared <- sapply(lm_models, function(model) {
rsq <- summary(model)$r.squared
return(rsq)
})
rsquared_df <- data.frame(PC = 1:10, R2 = rsquared)
return(rsquared_df)
}
# Function to create scatter plot and convert to plotly
scatter_to_plotly <- function(data, x_col, y_col, color_col, title) {
p <- ggplot(data, aes_string(x = x_col, y = y_col, color = color_col)) +
geom_point(size = 0.5) +
scale_color_manual(values = color_palette, guide = guide_legend(override.aes = list(size = 2))) +
labs(x = x_col, y = y_col, title = title) +
theme_bw()
return(ggplotly(p))
}
calculatePairwiseDistancesAndPlotDensity <- function(query_data, ref_data, query_cell_type_col, ref_cell_type_col, cell_type_query, cell_type_reference,distance_metric, correlation_method = "pearson") {
# Subset query and reference data to the specified cell type
query_data_subset <- query_data[, !is.na(query_data[[query_cell_type_col]]) & query_data[[query_cell_type_col]] == cell_type_query]
ref_data_subset <- ref_data[, !is.na(ref_data[[ref_cell_type_col]]) & ref_data[[ref_cell_type_col]] == cell_type_reference]
# Convert to matrix
query_mat <- t(as.matrix(assay(query_data_subset, "logcounts")))
ref_mat <- t(as.matrix(assay(ref_data_subset, "logcounts")))
# Combine query and reference matrices
combined_mat <- rbind(query_mat, ref_mat)
# Calculate pairwise distances or correlations for all comparisons
if (distance_metric == "correlation") {
if (correlation_method == "pearson") {
dist_matrix <- cor(t(combined_mat), method = "pearson")
} else if (correlation_method == "spearman") {
dist_matrix <- cor(t(combined_mat), method = "spearman")
} else {
stop("Invalid correlation method. Available options: 'pearson', 'spearman'")
}
} else {
dist_matrix <- dist(combined_mat, method = distance_metric)
}
# Convert dist_matrix to a square matrix
dist_matrix <- as.matrix(dist_matrix)
# Extract the distances or correlations for the different pairwise comparisons
num_query_cells <- nrow(query_mat)
num_ref_cells <- nrow(ref_mat)
dist_query_query <- dist_matrix[1:num_query_cells, 1:num_query_cells]
dist_ref_ref <- dist_matrix[(num_query_cells+1):(num_query_cells+num_ref_cells), (num_query_cells+1):(num_query_cells+num_ref_cells)]
dist_query_ref <- dist_matrix[1:num_query_cells, (num_query_cells+1):(num_query_cells+num_ref_cells)]
# Create data frame for plotting
dist_df <- data.frame(
Comparison = c(rep("Query vs Query", length(dist_query_query)),
rep("Reference vs Reference", length(dist_ref_ref)),
rep("Query vs Reference", length(dist_query_ref))),
Distance = c(as.vector(dist_query_query),
as.vector(dist_ref_ref),
as.vector(dist_query_ref))
)
# Plot density plots
ggplot(dist_df, aes(x = Distance, color = Comparison)) +
geom_density() +
labs(x = ifelse(distance_metric == "correlation", paste(correlation_method, "correlation"), "Distance"), y = "Density", title = "Pairwise Distance Analysis and Density Visualization") +
theme_bw()
}
Visualizing Regression Results
Note: Here original/observed query data cell labels are used.
We visualize the outcome of the regression analysis by creating line
plots that depict the R-squared values for each principal component.
PC1: The high R-squared value indicates that a significant portion of
the variability in PC1 is explained by the cell labels. This suggests
that PC1 captures meaningful differences between the cell types.
PC2: Captures a substantial amount of variation related to cell
labels. This component contributes significantly to distinguishing
between different cell types.
PC3: The R-squared value of PC3 indicates that it still captures a
moderate amount of variation explained by cell labels, although it is
less influential than PC1 and PC2.
PC4 to PC10: The R-squared values for PC4 to PC10 are relatively
lower, ranging from 0.0366 to 0.0073. These components capture much less
of the variation explained by the cell labels. Their low R-squared
values might suggest that these principal components might be influenced
by other factors not accounted for by the provided cell labels
# Data preparation
query_observed <- data.frame(reducedDim(query, "PCA"), CellTypes = query$label)
rsquared_df <- regress_PCs(query_observed)
# Create a line plot using ggplot
ggplot(rsquared_df, aes(x = PC, y = R2)) +
geom_line() +
geom_point(shape = 16) +
labs(x = "Principal Component (PC)",
y = "R-squared",
title = "R-squared for Principal Components") +
ylim(0, 1) +
theme_bw() +
scale_x_continuous(breaks = 1:10, labels = 1:10)

Scatter plots between different PCs for query dataset (Observed
query dataset)
# Define color palette
seeds <- c("#FF0000FF", "#CCFF00FF", "#00FF66FF", "#0066FFFF", "#CC00FFFF")
color_palette <- createPalette(length(unique(query_observed$CellType)), seeds)
names(color_palette) <- unique(query_observed$CellType)
PC1 vs PC2 scatter plot
The scatter plot of PC1 vs PC2 indicates that there are separate
clusters for NK cells and CD14 cells, which means that these two cell
types are well-separated from the others in this two-dimensional space
defined by PC1 and PC2. This separation suggests that PC1 and PC2
capture distinct variations that allow for distinguishing between NK
cells and CD14 cells from other cell types.
scatter_to_plotly(query_observed, "PC1", "PC2", "CellTypes", "PC1 vs PC2")
PC1 vs PC3 scatter plot
The variation captured by PC3 contributes to the separation of CD14
cells from other cell types when looking at the plot with PC3.
scatter_to_plotly(query_observed, "PC3", "PC1", "CellTypes", "PC1 vs PC3")
PC1 vs PC4 scatter plot
Similar to above results, the variation captured by PC4 contributes
to the separation of CD14 cells from other cell types.
scatter_to_plotly(query_observed, "PC4", "PC1", "CellTypes", "PC1 vs PC4")
PC4 vs PC5 scatter plot
Plot of PC4 vs PC5 shows a mixed pattern with no clear separation or
clustering of cell types, suggesting that the variation captured by
these PCs may not have a strong discriminatory effect on the different
cell types in the dataset.
scatter_to_plotly(query_observed, "PC4", "PC5", "CellTypes", "PC4 vs PC5")
Boxplots of PC1 vs Cell types
CD14 cells might exhibit distinct molecular characteristics that set
them apart from the other three cell types.
ggplot(query_observed, aes(x = CellTypes, y = PC1, fill = CellTypes)) +
geom_boxplot() +
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
guides(fill = "none") +
xlab("CellTypes") +
ylab("PC1") + geom_hline(yintercept = 0, linetype = "dashed", color = "red")

Boxplots of PC2 vs Cell types
These results indicate that NK cells might exhibit distinct gene
expression patterns or molecular characteristics captured by PC2.
ggplot(query_observed, aes(x = CellTypes, y = PC2, fill = CellTypes)) +
geom_boxplot() +
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
guides(fill = "none") +
xlab("CellTypes") +
ylab("PC2") + geom_hline(yintercept = 0, linetype = "dashed", color = "red")

Boxplots of PC3 vs Cell types
ggplot(query_observed, aes(x = CellTypes, y = PC3, fill = CellTypes)) +
geom_boxplot() +
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
guides(fill = "none") +
xlab("CellTypes") +
ylab("PC3") + geom_hline(yintercept = 0, linetype = "dashed", color = "red")

Query dataset when CD4 cell type is removed from reference
dataset
In this section, we focus on the query dataset that was generated
after removing CD4 cell types from the reference dataset. We perform
analysis on this modified dataset to explore how the Principal
Components (PCs) relate to the predicted cell labels.
PC1 captures a high amount of variance, suggesting that it explains a
substantial portion of the variability in the data.
PC2 also captures a significant amount of variance, indicating its
importance in explaining variability.
The R-squared values for PC3 to PC10 are much lower, indicating that
these components capture relatively less variance in the data.
# Data preparation
query1 <- data.frame(reducedDim(query, "PCA"), CellTypes = tab[[1]]$annotations$labels)
rsquared_df <- regress_PCs(query1)
# Create a line plot using ggplot
ggplot(rsquared_df, aes(x = PC, y = R2)) +
geom_line() +
geom_point(shape = 16) +
labs(x = "Principal Component (PC)",
y = "R-squared",
title = "R-squared for Principal Components (CD4 cells removed from reference dataset)") +
ylim(0, 1) +
theme_bw() +
scale_x_continuous(breaks = 1:10, labels = 1:10)

Scatter plots between different PCs for query dataset (from
reference CD4 cells removed)
We create scatter plots to visualize the PCA results for the query
dataset with CD4 cell types removed from the reference.
# Define color palette
seeds <- c("#FF0000FF", "#CCFF00FF", "#00FF66FF", "#0066FFFF", "#CC00FFFF")
color_palette <- createPalette(length(unique(query1$CellType)), seeds)
names(color_palette) <- unique(query1$CellType)
PC1 vs PC2 scatter plot
The scatter plot of PC1 vs PC2 for the query dataset with CD4 cell
types removed from the reference demonstrates a distinct separation of
clusters. This separation suggests that the variations captured by PC1
and PC2 are effective at distinguishing different cell types in the
query dataset.
scatter_to_plotly(query1, "PC1", "PC2", "CellTypes", "PC1 vs PC2")
PC1 vs PC3 scatter plot
The separation of CD14 cells from the others along the PC3 axis is
notable, indicating that the variation captured by PC3 contributes
significantly to distinguishing CD14 cells from the rest. Additionally,
the proximity of CD8 and NK cells along the PC3 axis suggests that these
cell types may share some common gene expression patterns or molecular
characteristics captured by PC3.
Also, concordance plot above revealed that when CD8 cells were
removed from the reference dataset, a small subset of cells in the query
dataset were being assigned as NK cells.
scatter_to_plotly(query1, "PC3", "PC1", "CellTypes", "PC1 vs PC3")
PC2 vs PC3 scatter plot
Separation of NK cells from other cell types seems to be influenced
by both PC2 and PC3,
scatter_to_plotly(query1, "PC3", "PC2", "CellTypes", "PC3 vs PC2")
Boxplots of PC1 vs Cell types
ggplot(query1, aes(x = CellTypes, y = PC1, fill = CellTypes)) +
geom_boxplot() +
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
guides(fill = "none") +
xlab("CellTypes") +
ylab("PC1") + geom_hline(yintercept = 0, linetype = "dashed", color = "red")

Boxplots of PC2 vs Cell types
ggplot(query1, aes(x = CellTypes, y = PC1, fill = CellTypes)) +
geom_boxplot() +
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
guides(fill = "none") +
xlab("CellTypes") +
ylab("PC2") + geom_hline(yintercept = 0, linetype = "dashed", color = "red")

Boxplots of PC3 vs Cell types
ggplot(query1, aes(x = CellTypes, y = PC1, fill = CellTypes)) +
geom_boxplot() +
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
guides(fill = "none") +
xlab("CellTypes") +
ylab("PC3") + geom_hline(yintercept = 0, linetype = "dashed", color = "red")

Query dataset when CD14 cell type is removed from reference
dataset
In this section, we focus on the query dataset that was generated
after removing CD14 cell types from the reference dataset. We perform
analysis on this modified dataset to explore how the Principal
Components (PCs) derived from PCA relate to the predicted cell
labels.
PC1 explains approximately 11.06% of the total variance in the data.
This value suggests that PC1 captures a moderate amount of variation in
the dataset. While not extremely high, it still contributes
significantly to the understanding of the differences among the data
points.
PC2 explains approximately 86.10% of the total variance in the data.
This high R-squared value indicates that PC2 captures a substantial
amount of variation in the dataset. PC2 is a dominant component in
explaining the differences among the data points.
PC3 explains approximately 44.17% of the total variance in the data.
This value indicates that PC3 captures a moderate to high amount of
variation in the dataset.
PC4 to PC10 each explain less than 10% of the total variance in the
data. These components contribute relatively little to the overall
variance and might capture noise or less significant patterns in the
dataset.
# Data preparation
query2 <- data.frame(reducedDim(query, "PCA"), CellTypes = tab[[2]]$annotations$labels)
rsquared_df <- regress_PCs(query2)
# Create a line plot using ggplot
ggplot(rsquared_df, aes(x = PC, y = R2)) +
geom_line() +
geom_point(shape = 16) +
labs(x = "Principal Component (PC)",
y = "R-squared",
title = "R-squared for Principal Components (CD14 cells removed from reference dataset)") +
ylim(0, 1) +
theme_bw() +
scale_x_continuous(breaks = 1:10, labels = 1:10)

Scatter plots between different PCs for query dataset (from
reference CD14 cells removed)
We create scatter plots to visualize the PCA results for the query
dataset with CD14 cell types removed from the reference.
# Define color palette
seeds <- c("#FF0000FF", "#CCFF00FF", "#00FF66FF", "#0066FFFF", "#CC00FFFF")
color_palette <- createPalette(length(unique(query2$CellType)), seeds)
names(color_palette) <- unique(query2$CellType)
PC1 vs PC2 scatter plot
In the scatter plot of PC1 vs PC2 for the query dataset (with
reference CD14 cells removed), the following observations can be
made:
Two Populations/Clusters of CD8 Cells: There are two distinct
clusters or populations of CD8 cells visible on the plot. One of these
clusters overlaps with CD4 cells, indicating some degree of similarity
in their gene expression patterns.
NK cells are well-separated from the other cell types, suggesting
that the variation captured by PC1 and PC2 is effective in
distinguishing NK cells from the rest.
scatter_to_plotly(query2, "PC1", "PC2", "CellTypes", "PC1 vs PC2")
PC1 vs PC4 scatter plot
scatter_to_plotly(query2, "PC4", "PC1", "CellTypes", "PC1 vs PC4")
PC2 vs PC4 scatter plot
scatter_to_plotly(query2, "PC4", "PC2", "CellTypes", "PC4 vs PC2")
Boxplots of PC1 vs Cell types
The boxplots of PC1 values for different cell types reveal that the
CD8 population exhibits a larger spread or variability along the PC1
axis compared to the CD4 and NK populations. This suggests that there
might be greater heterogeneity or diversity within the CD8 cell
population in terms of the gene expression patterns captured by PC1. On
the other hand, the CD4 and NK populations seem to be more tightly
clustered or have less variation along PC1.
ggplot(query2, aes(x = CellTypes, y = PC1, fill = CellTypes)) +
geom_boxplot() +
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
guides(fill = "none") +
xlab("CellTypes") +
ylab("PC1") + geom_hline(yintercept = 0, linetype = "dashed", color = "red")

Boxplots of PC2 vs Cell types
PC2 contributes to the separation of NK cells from the other two cell
types.
ggplot(query2, aes(x = CellTypes, y = PC2, fill = CellTypes)) +
geom_boxplot() +
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
guides(fill = "none") +
xlab("CellTypes") +
ylab("PC2") + geom_hline(yintercept = 0, linetype = "dashed", color = "red")

Query dataset when CD8 cell type is removed from reference
dataset
In this section, we focus on the query dataset that was generated
after removing CD8 cell types from the reference dataset. We perform
analysis on this modified dataset to explore how the Principal
Components (PCs) derived from PCA relate to the predicted cell
labels.
From the plot, we can see that PC1 and PC2 capture the majority of
the variance in the data, with PC1 explaining the most variance. The
subsequent PCs (PC3 to PC10) capture less variance and may represent
smaller or more subtle patterns in the data.
# Data preparation
query3 <- data.frame(reducedDim(query, "PCA"), CellTypes = tab[[3]]$annotations$labels)
rsquared_df <- regress_PCs(query3)
# Create a line plot using ggplot
ggplot(rsquared_df, aes(x = PC, y = R2)) +
geom_line() +
geom_point(shape = 16) +
labs(x = "Principal Component (PC)",
y = "R-squared",
title = "R-squared for Principal Components (CD8 cells removed from reference dataset)") +
ylim(0, 1) +
theme_bw() +
scale_x_continuous(breaks = 1:10, labels = 1:10)

Scatter plots between different PCs for query dataset (from
reference CD8 cells removed)
We created scatter plots to visualize the PCA results for the query
dataset with CD8 cell types removed from the reference.
# Define color palette
seeds <- c("#FF0000FF", "#CCFF00FF", "#00FF66FF", "#0066FFFF", "#CC00FFFF")
color_palette <- createPalette(length(unique(query3$CellType)), seeds)
names(color_palette) <- unique(query3$CellType)
PC1 vs PC2 scatter plot
The scatter plot of PC1 against PC2 for the query dataset, with
reference CD8 cells removed, shows clear separation between different
cell types. This separation could indicate that the variability captured
by PC1 and PC2 is significant enough to differentiate between the
remaining cell types in your dataset.
scatter_to_plotly(query3, "PC1", "PC2", "CellTypes", "PC1 vs PC2")
PC1 vs PC3 scatter plot
CD14 cells are separated from the other cell types along the PC3
axis. This indicates that the variation captured by PC3 contributes
significantly to the differences between CD14 cells and the rest.
scatter_to_plotly(query3, "PC3", "PC1", "CellTypes", "PC1 vs PC3")
PC2 vs PC3 scatter plot
scatter_to_plotly(query3, "PC3", "PC2", "CellTypes", "PC2 vs PC3")
Boxplots of PC1 vs Cell types
ggplot(query3, aes(x = CellTypes, y = PC1, fill = CellTypes)) +
geom_boxplot() +
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
guides(fill = "none") +
xlab("CellTypes") +
ylab("PC1") + geom_hline(yintercept = 0, linetype = "dashed", color = "red")

Boxplots of PC2 vs Cell types
ggplot(query3, aes(x = CellTypes, y = PC2, fill = CellTypes)) +
geom_boxplot() +
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
guides(fill = "none") +
xlab("CellTypes") +
ylab("PC2") + geom_hline(yintercept = 0, linetype = "dashed", color = "red")

Boxplots of PC3 vs Cell types
ggplot(query3, aes(x = CellTypes, y = PC3, fill = CellTypes)) +
geom_boxplot() +
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
guides(fill = "none") +
xlab("CellTypes") +
ylab("PC3") + geom_hline(yintercept = 0, linetype = "dashed", color = "red")

Query dataset when NK cell type is removed from reference
dataset
In this section, we focus on the query dataset that was generated
after removing NK cell types from the reference dataset. We perform
analysis on this modified dataset to explore how the Principal
Components (PCs) derived from PCA relate to the predicted cell
labels.
PC1 has an R-squared value of 0.949, indicating that it captures a
substantial amount of variation in the dataset. It suggests that PC1
explains a large portion of the total variability.
PC2 has an R-squared value of 0.185, which is significantly lower
than PC1. This means that PC2 explains a smaller portion of the total
variability compared to PC1.
PC3 has an R-squared value of 0.396, indicating that it captures a
moderate amount of variation. It’s higher than PC2 but not as high as
PC1.
PCs 4 to 10 have much lower R-squared values ranging from 0.024 to
0.001, suggesting that they explain relatively small amounts of
variation in the dataset.
# Data preparation
query4 <- data.frame(reducedDim(query, "PCA"), CellTypes = tab[[4]]$annotations$labels)
rsquared_df <- regress_PCs(query4)
# Create a line plot using ggplot
ggplot(rsquared_df, aes(x = PC, y = R2)) +
geom_line() +
geom_point(shape = 16) +
labs(x = "Principal Component (PC)",
y = "R-squared",
title = "R-squared for Principal Components (NK cells removed from reference dataset)") +
ylim(0, 1) +
theme_bw() +
scale_x_continuous(breaks = 1:10, labels = 1:10)

Scatter plots between different PCs for query dataset (from
reference NK cells removed)
We create scatter plots to visualize the PCA results for the query
dataset with NK cell types removed from the reference.
# Define color palette
seeds <- c("#FF0000FF", "#CCFF00FF", "#00FF66FF", "#0066FFFF", "#CC00FFFF")
color_palette <- createPalette(length(unique(query4$CellType)), seeds)
names(color_palette) <- unique(query4$CellType)
PC1 vs PC2 scatter plot
CD14 cells are well separated from the other cell types along the PC1
axis.
There are two distinct populations of CD8 cells: one population is
somewhat separate from the other, and the latter population has some
overlap with CD4 cells.
scatter_to_plotly(query4, "PC1", "PC2", "CellTypes", "PC1 vs PC2")
PC1 vs PC3 scatter plot
CD14 cells continue to show a clear separation from the other cell
types, indicating distinct differences in gene expression patterns or
other molecular characteristics.
scatter_to_plotly(query4, "PC3", "PC1", "CellTypes", "PC1 vs PC3")
PC1 vs PC4 scatter plot
scatter_to_plotly(query4, "PC4", "PC1", "CellTypes", "PC1 vs PC4")
PC2 vs PC3 scatter plot
scatter_to_plotly(query4, "PC3", "PC2", "CellTypes", "PC3 vs PC2")
PC3 vs PC4 scatter plot
scatter_to_plotly(query4, "PC3", "PC4", "CellTypes", "PC3 vs PC4")
Boxplots of PC1 vs Cell types
PC1 captures significant variation that distinguishes CD14 cells from
CD4 and CD8 cells.
ggplot(query4, aes(x = CellTypes, y = PC1, fill = CellTypes)) +
geom_boxplot() +
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
guides(fill = "none") +
xlab("CellTypes") +
ylab("PC1") + geom_hline(yintercept = 0, linetype = "dashed", color = "red")

Boxplots of PC2 vs Cell types
The following analysis reveals:
CD8 Cell Population Spread: The noticeable spread in the CD8 cell
population along PC2 indicates that there is significant variability in
the gene expression or molecular characteristics of CD8 cells that is
captured by this principal component. This spread might suggest that
there are subgroups or subtypes within the CD8 cell population that
exhibit distinct patterns along PC2.
Two CD8 Cell Populations: The presence of two distinct CD8 cell
populations in the PC1 vs PC2 scatter plot aligns with the spread seen
in the boxplots of PC2 vs Cell types. This suggests that the variation
captured by PC2 contributes to the differentiation between these two CD8
cell populations. The spread seen in the boxplots might be attributed to
the differences between these populations in terms of the captured
variation along PC2.
ggplot(query4, aes(x = CellTypes, y = PC2, fill = CellTypes)) +
geom_boxplot() +
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
guides(fill = "none") +
xlab("CellTypes") +
ylab("PC2") + geom_hline(yintercept = 0, linetype = "dashed", color = "red")

Boxplots of PC3 vs Cell types
ggplot(query4, aes(x = CellTypes, y = PC3, fill = CellTypes)) +
geom_boxplot() +
theme_bw() +
theme(axis.text.x = element_text(angle = 90, hjust = 1)) +
guides(fill = "none") +
xlab("CellTypes") +
ylab("PC3") + geom_hline(yintercept = 0, linetype = "dashed", color = "red")

Distance analysis between distinct cell types of reference and query
dataset
Note: Distances are being calculated for cell types in
original/observed reference and query dataset.
Identified marker genes using trainSingleR() function from SingleR
package and used these genes to compute distances between cells in
reference and query dataset.
Distance between CD4 cells in reference and query
calculatePairwiseDistancesAndPlotDensity(query_subset, reference_subset, "label", "label", "CD4", "CD4", "euclidean")

Distance between CD14 cells in reference and query
calculatePairwiseDistancesAndPlotDensity(query_subset, reference_subset, "label", "label", "CD14", "CD14", "euclidean")

Distance between CD8 cells in reference and query
calculatePairwiseDistancesAndPlotDensity(query_subset, reference_subset, "label", "label", "CD8", "CD8", "euclidean")

Distance between NK cells in reference and query
calculatePairwiseDistancesAndPlotDensity(query_subset, reference_subset, "label", "label", "NK", "NK", "euclidean")

Distance analysis between cell types removed from reference and
assigned cell type in query dataset
In this section, we calculate Euclidean distances between the removed
cell types in the reference and their assigned cell types in the
query.
# Extract labels from each element in the 'tab' list using lapply
label_lists <- lapply(tab, function(x) x$annotations$labels)
annotations <- do.call(data.frame, label_lists)
colnames(annotations) <- c("labels_CD4_removed", "labels_CD14_removed", "labels_CD8_removed", "labels_NK_removed")
Distance computation between CD4 cells in query and CD8 cells in
reference
When, CD8 cells were removed from the reference and when this
reference was used to annotate the query dataset, these cells were
assigned as CD4 in query.
calculatePairwiseDistancesAndPlotDensity(query_subset, reference_subset, "labels_CD4_removed", "label", "CD8", "CD4", "euclidean")

Distance computation between CD8 cells in query and CD14 cells in
reference
When, CD14 cells were removed from the reference and when this
reference was used to annotate the query dataset, these cells were
assigned as CD8 in query.
calculatePairwiseDistancesAndPlotDensity(query_subset, reference_subset, "labels_CD14_removed", "label", "CD8", "CD14", "euclidean")

Distance computation between CD4 cells in query and CD8 cells in
reference
When, CD8 cells were removed from the reference and when this
reference was used to annotate the query dataset, these cells were
assigned as CD4 in query.
calculatePairwiseDistancesAndPlotDensity(query_subset, reference_subset, "labels_CD8_removed", "label", "CD4", "CD8", "euclidean")

Distance computation between CD8 cells in query and NK cells in
reference
When, NK cells were removed from the reference and when this
reference was used to annotate the query dataset, these cells were
assigned as CD8 in query.
calculatePairwiseDistancesAndPlotDensity(query_subset, reference_subset, "labels_NK_removed", "label", "CD8", "NK", "euclidean")

Principal Component Analysis (PCA) Key Observations:
CD4 and CD8 Overlap in PC1 vs PC2 in the Query: The overlap observed
between CD4 and CD8 cells in the PC1 vs PC2 plot of the query dataset
suggests the presence of shared gene expression patterns between these
two cell types. This shared pattern might lead to their proximity in the
PCA space.
CD14, CD8, and NK Separation in PC1 vs PC2 After CD4 Removal: Upon
removing CD4 cells from the reference dataset, there is an improved
separation of CD14, CD8, and NK cells in the PC1 vs PC2 plot. This
enhancement in separation could be attributed to the reduction of noise
caused by CD4 cells, enabling a clearer distinction between these cell
populations.
Two CD8 Populations in PC2 vs PC3 After CD4 Removal: The absence of
CD4 cells from the reference dataset has uncovered previously masked
heterogeneity within CD8 cells. This is evident from the emergence of
two distinct CD8 subpopulations in the PC2 vs PC3 plot, indicating that
CD4 cells were influencing the grouping of CD8 cells.
Two CD8 Populations in PC1 vs PC2 After CD14 Removal: Following the
removal of CD14, there are notable changes in the variance captured by
PC1 and PC2. This unmasking of variability has led to the identification
of two distinct CD8 subpopulations in the PC1 vs PC2 plot, suggesting
that CD14 cells were masking this heterogeneity.
Two CD4 Populations in PC2 vs PC3 After CD8 Removal: The absence of
CD8 T cells in the reference dataset has revealed hidden variability
within CD4 T cells. This is evident from the appearance of two distinct
CD4 subpopulations in the PC2 vs PC3 plot, highlighting that the
presence of CD8 cells was impacting the representation of CD4 cells.
Two CD8 Populations in PC1 vs PC2 After NK Removal: Removing NK cells
from the reference dataset has had an influence on the positioning of
CD8 T cells in the PCA space. This effect is seen in the emergence of
two CD8 cell populations in the PC1 vs PC2 plot, indicating that the
presence of NK cells was affecting the distribution of CD8 cells.
Distinct CD4, CD14, and CD8 Populations in PC1 vs PC3 After NK
Removal: The removal of NK cells from the reference dataset has brought
about clearer separation between CD4 T cells, CD14, and CD8 cells in the
PC1 vs PC3 plot. The masking effect of NK cells on the distinction
between these populations has been alleviated.
Two CD8 Populations in PC2 vs PC3 After CD4 Removal: The absence of
CD4 cells in the reference dataset has allowed for the identification of
subtle heterogeneity within CD8 in the PC2 vs PC3 plot. This finding
underscores how the presence of CD4 cells was impacting the
representation of CD8 cell variability.
LS0tCnRpdGxlOiAiUHJpbmNpcGFsIENvbXBvbmVudCBBbmFseXNpcyBvbiBRdWVyeSBEYXRhc2V0IE1hcHBlZCBVc2luZyBSZWZlcmVuY2UsIHdpdGggT25lIENlbGwgVHlwZSBSZW1vdmVkIgpkYXRlOiAiMjAyMy0wNi0yMSIKb3V0cHV0OgogIGh0bWxfZG9jdW1lbnQ6CiAgICB0aGVtZTogc3BhY2VsYWIKICAgIGhpZ2hsaWdodDogZGVmYXVsdAogICAgY29kZV9kb3dubG9hZDogdHJ1ZQogICAgdG9jOiB0cnVlCiAgICB0b2NfZGVwdGg6IDMKICAgIHRvY19mbG9hdDogCiAgICAgICAgICAgIGNvbGxhcHNlZDogZmFsc2UKLS0tCiAgCmBgYHtyIHNldHVwLCBpbmNsdWRlPUZBTFNFfQprbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IFRSVUUpCmBgYAoKIyBTdW1tYXJ5IG9mIEFuYWx5c2lzCgpJbiB0aGlzIGFuYWx5c2lzLCB3ZSBpbnZlc3RpZ2F0ZSB0aGUgaW1wYWN0IG9mIHJlbW92aW5nIHNwZWNpZmljIGNlbGwgdHlwZXMgZnJvbSB0aGUgcmVmZXJlbmNlIGRhdGFzZXQgYW5kIG1hcHBpbmcvcXVlcnlpbmcgdGhlbSB1c2luZyB0aGUgbW9kaWZpZWQgcmVmZXJlbmNlLiBUaGUgbWFpbiBzdGVwcyBpbmNsdWRlOgoKQ2VsbCBUeXBlIFJlbW92YWw6IENENCwgQ0Q4LCBDRDE0LCBhbmQgTksgY2VsbCB0eXBlcyBhcmUgc3lzdGVtYXRpY2FsbHkgcmVtb3ZlZCBmcm9tIHRoZSByZWZlcmVuY2UgZGF0YXNldC4KCk1hcHBpbmcgYW5kIFF1ZXJ5aW5nOiBVdGlsaXppbmcgdGhlIG1vZGlmaWVkIHJlZmVyZW5jZSwgd2UgbWFwIHRoZSBxdWVyeSBkYXRhc2V0LgoKUHJpbmNpcGFsIENvbXBvbmVudCBSZWdyZXNzaW9uOiBSZWdyZXNzaW9uIG9mIHByaW5jaXBhbCBjb21wb25lbnRzIChQQ3MpIGFnYWluc3QgcHJlZGljdGVkIGNlbGwgdHlwZXMgaXMgcGVyZm9ybWVkLiBXZSB2aXN1YWxpemUgUEMgc2NhdHRlciBwbG90cyBhbmQgYm94IHBsb3RzLgoKRGlzdGFuY2UgQ2FsY3VsYXRpb246IENhbGN1bGF0aW9uIG9mIEV1Y2xpZGVhbiBkaXN0YW5jZXMgYmV0d2VlbiB0aGUgY2VsbCB0eXBlcyBpbiB0aGUgcmVmZXJlbmNlIGFuZCB0aGUgY29ycmVzcG9uZGluZyBjZWxsIHR5cGVzIGluIHRoZSBxdWVyeS4KCkludGVyLUNlbGwgVHlwZSBEaXN0YW5jZXM6IENvbXB1dGF0aW9uIG9mIGRpc3RhbmNlcyBiZXR3ZWVuIHRoZSBjZWxsIHR5cGVzIHJlbW92ZWQgZnJvbSB0aGUgcmVmZXJlbmNlIGFuZCB0aGUgY2VsbCB0eXBlcyB0byB3aGljaCB0aGV5IHdlcmUgYXNzaWduZWQgaW4gdGhlIHF1ZXJ5LgoKIyBJbnRyb2R1Y3Rpb24KCldlbGNvbWUgdG8gdGhpcyBkb2N1bWVudCwgd2hlcmUgd2UgZGVsdmUgaW50byB0aGUgcmVzdWx0cyBvZiBhIHJlZ3Jlc3Npb24gYW5hbHlzaXMgaW52b2x2aW5nIFByaW5jaXBhbCBDb21wb25lbnRzIChQQ3MpIGFuZCBjZWxsIGxhYmVscy4gT3VyIGV4cGxvcmF0aW9uIGVuY29tcGFzc2VzIHR3byBkaXN0aW5jdCBzY2VuYXJpb3M6CgpSZWdyZXNzaW9uIG9mIFBDcyBhZ2FpbnN0IE9ic2VydmVkIENlbGwgTGFiZWxzIGluIFF1ZXJ5IERhdGFzZXQ6IFRoaXMgc2NlbmFyaW8gaW52b2x2ZXMgdGhlIHJlZ3Jlc3Npb24gb2YgUHJpbmNpcGFsIENvbXBvbmVudHMgYWdhaW5zdCB0aGUgYWN0dWFsIGNlbGwgbGFiZWxzIHdpdGhpbiB0aGUgcXVlcnkgZGF0YXNldC4KClJlZ3Jlc3Npb24gb2YgUENzIGFnYWluc3QgUHJlZGljdGVkIENlbGwgTGFiZWxzIGluIFF1ZXJ5IERhdGFzZXQ6IEluIHRoaXMgc2NlbmFyaW8sIHdlIHBlcmZvcm0gcmVncmVzc2lvbiBvZiBQcmluY2lwYWwgQ29tcG9uZW50cyBhZ2FpbnN0IHByZWRpY3RlZCBjZWxsIGxhYmVscyBpbiB0aGUgcXVlcnkgZGF0YXNldC4gVGhlc2UgcHJlZGljdGVkIGxhYmVscyBhcmUgZGVyaXZlZCBmcm9tIHN5c3RlbWF0aWNhbGx5IGV4Y2x1ZGluZyBvbmUgY2VsbCBhdCBhIHRpbWUgZnJvbSB0aGUgcmVmZXJlbmNlIGRhdGFzZXQuIFRoZSBtb2RpZmllZCByZWZlcmVuY2UgaXMgdGhlbiBlbXBsb3llZCB0byBtYXAgdGhlIHF1ZXJ5IGRhdGFzZXQuCgpUaGUgYW5hbHlzaXMgaGluZ2VzIG9uIGEgU2luZ2xlLUNlbGwgUk5BIHNlcXVlbmNpbmcgKHNjUk5BLXNlcSkgMTB4IEdlbm9taWNzIFBCTUMgZGF0YXNldC4gVGhpcyBkYXRhc2V0IGlzIGRpdmlkZWQgaW50byB0d28gc3Vic2V0czogdGhlIHJlZmVyZW5jZSBzZXQgKDEweCBTaW5nbGUtQ2VsbCBSTkFzZXEgUEJNQ3MgLSBSZWZlcmVuY2UpIGFuZCB0aGUgcXVlcnkgZGF0YXNldCAoMTB4IFNpbmdsZS1DZWxsIFJOQXNlcSBQQk1DcyAtIFdpdGhoZWxkIFRlc3QgU2V0KS4gVGhlIGRhdGFzZXQgY2FuIGJlIGFjY2Vzc2VkIGZyb20gdGhlIGZvbGxvd2luZyBsaW5rOiBodHRwczovL2ZpZ3NoYXJlLmNvbS9wcm9qZWN0cy9DdXJhdGVkXzEwWF9EYXRhLzEzNzg5MgoKCmBgYHtyIExpYnJhcmllcywgd2FybmluZz1GQUxTRSxtZXNzYWdlPUZBTFNFfQpsaWJyYXJ5KFNpbmdsZVIpCmxpYnJhcnkoc2NhdGVyKQpsaWJyYXJ5KFBvbHljaHJvbWUpCmxpYnJhcnkocGxvdGx5KQpsaWJyYXJ5KGdncGxvdDIpCmBgYAoKIyBEYXRhIFByb2Nlc3NpbmcKCkluIHRoaXMgc2VjdGlvbiwgd2UgbG9hZCB0aGUgcmVmZXJlbmNlIGFuZCB3aXRoaGVsZCBkYXRhc2V0cywgbG9nLXRyYW5zZm9ybSB0aGUgZGF0YSwgYW5kIGV4cGxvcmUgdGhlIGltcGFjdCBvZiByZW1vdmluZyBkaWZmZXJlbnQgY2VsbCB0eXBlcyBmcm9tIHRoZSByZWZlcmVuY2UgZGF0YXNldCBvbiBwcmVkaWN0aW9uIGFjY3VyYWN5LgoKYGBge3IgRGF0YSBwcm9jZXNzaW5nLCBlY2hvPUYsIHdhcm5pbmc9Rn0KIyBMb2FkIHJlZmVyZW5jZSBhbmQgd2l0aGhlbGQgZGF0YXNldHMKbG9hZCgifi9Eb3dubG9hZHMvMTB4X3BibWNzX3JlZmVyZW5jZV9zY2UucmRhIikKbG9hZCgifi9Eb3dubG9hZHMvMTB4X3BibWNzX3dpdGhoZWxkX3NjZS5yZGEiKQoKIyBMb2cgdHJhbnNmb3JtIGRhdGFzZXRzCnJlZmVyZW5jZSA8LSBsb2dOb3JtQ291bnRzKHBibWNzX3JlZmVyZW5jZV9zY2UpCnF1ZXJ5IDwtIGxvZ05vcm1Db3VudHMocGJtY3Nfd2l0aGhlbGRfc2NlKQpgYGAKCiMgUENBIG9mIHJlZmVyZW5jZQoKYGBge3IgUENBIHJlZmVyZW5jZSwgZWNobz1GLCB3YXJuaW5nPUZ9CiMjIFJ1biBQQ0EKcmVmZXJlbmNlIDwtIHJ1blBDQShyZWZlcmVuY2UpCmRmX3JlZiA8LSBkYXRhLmZyYW1lKHJlZHVjZWREaW0ocmVmZXJlbmNlLCAiUENBIiksIENlbGxUeXBlID0gcmVmZXJlbmNlJGxhYmVsKQoKIyBHZW5lcmF0ZSBjb2xvcnMKc2VlZHMgPC0gYygiI0ZGMDAwMEZGIiwgIiNDQ0ZGMDBGRiIsICIjMDBGRjY2RkYiLCAiIzAwNjZGRkZGIiwgIiNDQzAwRkZGRiIpCmNvbHMgPC0gY3JlYXRlUGFsZXR0ZShsZW5ndGgodW5pcXVlKGRmX3JlZiRDZWxsVHlwZSkpLCBzZWVkcykKbmFtZXMoY29scykgPC0gdW5pcXVlKGRmX3JlZiRDZWxsVHlwZSkKCiMgUEMxIHZzIFBDMiBzY2F0dGVyIHBsb3QKcCA8LSBnZ3Bsb3QoZGZfcmVmLCBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgY29sb3IgPSBDZWxsVHlwZSkpICsKICAgZ2VvbV9wb2ludChzaXplID0gMC41KSArCiAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IGNvbHMsIGd1aWRlID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDIpKSkgKwogICAgIGxhYnMoeCA9ICJQQzEiLCB5ID0gIlBDMiIsIHRpdGxlID0gIlBDMSB2cyBQQzIgU2NhdHRlciBQbG90IikgKwogICAgIHRoZW1lX2J3KCkKZ2dwbG90bHkocCkKYGBgCgojIEFuYWx5c2lzIC0gUmVtb3ZpbmcgQ2VsbCBUeXBlcwoKSGVyZSwgd2UgYW5hbHl6ZSB0aGUgZWZmZWN0IG9mIHJlbW92aW5nIGluZGl2aWR1YWwgY2VsbCB0eXBlcyBmcm9tIHRoZSByZWZlcmVuY2UgZGF0YXNldCBvbiBwcmVkaWN0aW9uIGFjY3VyYWN5IHVzaW5nIHRoZSBTaW5nbGVSIHBhY2thZ2UuIFdlIGhhdmUgYSByZWZlcmVuY2UgZGF0YXNldCBjb250YWluaW5nIENENCwgQ0Q4LCBDRDE0LCBhbmQgTksgY2VsbCB0eXBlcy4gV2UgcmVtb3ZlIENENCBjZWxscyBmcm9tIHRoZSByZWZlcmVuY2UgYW5kIG1hcCBxdWVyeSB1c2luZyB0aGlzIHJlZmVyZW5jZS4gU2ltaWxhcmx5LCB0aGlzIHByb2Nlc3MgaXMgcGVyZm9ybWVkIGZvciBDRDgsIENEMTQsIGFuZCBOSyBjZWxscyBpbmRpdmlkdWFsbHksIGVhY2ggdGltZSByZW1vdmluZyBvbmUgY2VsbCB0eXBlIGFuZCBtYXBwaW5nIHF1ZXJ5IHdpdGggdGhpcyBtb2RpZmllZCByZWZlcmVuY2UuCgpgYGB7ciBBbmFseXNpcyAtIFJlbW92aW5nIENlbGwgVHlwZXMsIGVjaG89VCwgd2FybmluZz1GfQoKIyBSZW1vdmFsIG9mIG9uZSBjZWxsIHR5cGUgYXQgYSB0aW1lIGZyb20gcmVmZXJlbmNlCnRhYiA8LSBsYXBwbHkodW5pcXVlKHJlZmVyZW5jZSRsYWJlbCksIGZ1bmN0aW9uKGkpIHsKICBpbmR4IDwtIHdoaWNoKHJlZmVyZW5jZSRsYWJlbCA9PSBpKQogIHJlZm4gPC0gcmVmZXJlbmNlWywgLWluZHhdCiAgYW5ub3RhdGlvbnMgPC0gU2luZ2xlUihxdWVyeSwgcmVmID0gcmVmbiwgbGFiZWxzID0gcmVmbiRsYWJlbCkKICB0YWJsZV9yZXN1bHQgPC0gYXMuZGF0YS5mcmFtZSh0YWJsZShhbm5vdGF0aW9ucyRsYWJlbHMsIHF1ZXJ5JGxhYmVsKSkKICByZXR1cm4obGlzdChhbm5vdGF0aW9ucyA9IGFubm90YXRpb25zLCB0YWJsZV9yZXN1bHQgPSB0YWJsZV9yZXN1bHQpKQp9KQoKZGYgPC0gbWFwcGx5KGZ1bmN0aW9uKHRibF9yZXN1bHQsIGxhYmVsKSB7CiAgaW5keCA8LSB3aGljaCh0YmxfcmVzdWx0JFZhcjIgPT0gbGFiZWwpCiAgdGJsX3Jlc3VsdFtpbmR4LCBdCn0sIGxhcHBseSh0YWIsIGBbW2AsICJ0YWJsZV9yZXN1bHQiKSwgdW5pcXVlKHJlZmVyZW5jZSRsYWJlbCksIFNJTVBMSUZZID0gRkFMU0UpCgpkZiA9IGRvLmNhbGwocmJpbmQsIGRmKQpkZiA8LSBzdWJzZXQoZGYsIEZyZXEgPiAwKQoKIyBDb25jb3JkYW5jZSBwbG90CmRmJFZhcjIgPC0gZmFjdG9yKGRmJFZhcjIsIGxldmVscyA9IGMoIkNEOCIsICJOSyIsICJDRDQiLCAiQ0QxNCIpKQpnZ3Bsb3QoZGYsIGFlcyh4ID0gVmFyMSwgeSA9IFZhcjIsIHNpemUgPSBGcmVxKSkgKyAKICBnZW9tX3BvaW50KCkgKyAKICB4bGFiKCJQcmVkaWN0ZWQgbGFiZWxzIikgKyAKICB5bGFiKCJSZW1vdmVkIGxhYmVscyIpICsgCiAgdGhlbWVfYncoKSArIAogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCmBgYAoKClRoZSBzY2F0dGVyIHBsb3QgYWJvdmUgZGlzcGxheXMgcmVtb3ZlZCBjZWxsIHR5cGVzIGZyb20gcmVmZXJlbmNlIG9uIHkgYXhpcyBhbmQgcHJlZGljdGVkIGNlbGwgdHlwZSBvbiB4IApheGlzLiBGb3IgaW5zdGFuY2UsIGlmIGZyb20gcmVmZXJlbmNlIGRhdGFzZXQgQ0Q4IGNlbGxzIGFyZSByZW1vdmVkLCBJdCB3aWxsIGJlIHByZWRpY3RlZCBhcyBDRDQgY2VsbHMgaW4gYSBxdWVyeSBkYXRhc2V0LgoKIyBQQ0EgYW5kIFJlZ3Jlc3Npb24gYW5hbHlzaXMKCkluIHRoaXMgc2VjdGlvbiwgd2UgYXBwbHkgUENBIHRvIHRoZSBxdWVyeSBkYXRhc2V0IGFuZCBwZXJmb3JtIHJlZ3Jlc3Npb24gYW5hbHlzaXMgdG8gdW5kZXJzdGFuZCB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gcHJpbmNpcGFsIGNvbXBvbmVudHMgYW5kIG9ic2VydmVkIGNlbGwgbGFiZWxzIGZyb20gcXVlcnkgZGF0YXNldC4KCmBgYHtyIFJlZ3Jlc3Npb24gYW5hbHlzaXMsIGVjaG89VCwgd2FybmluZz1GfQpxdWVyeSA8LSBydW5QQ0EocXVlcnkpCgojIEZ1bmN0aW9uIHRvIHJlZ3Jlc3MgUENzIGFnYWluc3QgY2VsbCBsYWJlbHMKcmVncmVzc19QQ3MgPC0gZnVuY3Rpb24oZGF0YSkgewogIAogICMgQ2FsY3VsYXRlIFItc3F1YXJlZCB2YWx1ZXMKICBsbV9tb2RlbHMgPC0gbGFwcGx5KDE6MTAsIGZ1bmN0aW9uKGkpIHsKICAgIGxtX21vZGVsIDwtIGxtKHBhc3RlMCgiUEMiLCBpLCAiIH4gQ2VsbFR5cGVzIiksIGRhdGEgPSBkYXRhKQogICAgcmV0dXJuKGxtX21vZGVsKQogIH0pCiAgCiAgIyBDYWxjdWxhdGUgUi1zcXVhcmVkIHZhbHVlcwogIHJzcXVhcmVkIDwtIHNhcHBseShsbV9tb2RlbHMsIGZ1bmN0aW9uKG1vZGVsKSB7CiAgICByc3EgPC0gc3VtbWFyeShtb2RlbCkkci5zcXVhcmVkCiAgICByZXR1cm4ocnNxKQogIH0pCiAgCiAgcnNxdWFyZWRfZGYgPC0gZGF0YS5mcmFtZShQQyA9IDE6MTAsIFIyID0gcnNxdWFyZWQpCiAgcmV0dXJuKHJzcXVhcmVkX2RmKQp9CgojIEZ1bmN0aW9uIHRvIGNyZWF0ZSBzY2F0dGVyIHBsb3QgYW5kIGNvbnZlcnQgdG8gcGxvdGx5CnNjYXR0ZXJfdG9fcGxvdGx5IDwtIGZ1bmN0aW9uKGRhdGEsIHhfY29sLCB5X2NvbCwgY29sb3JfY29sLCB0aXRsZSkgewogIHAgPC0gZ2dwbG90KGRhdGEsIGFlc19zdHJpbmcoeCA9IHhfY29sLCB5ID0geV9jb2wsIGNvbG9yID0gY29sb3JfY29sKSkgKwogICAgZ2VvbV9wb2ludChzaXplID0gMC41KSArCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gY29sb3JfcGFsZXR0ZSwgZ3VpZGUgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID0gbGlzdChzaXplID0gMikpKSArCiAgICBsYWJzKHggPSB4X2NvbCwgeSA9IHlfY29sLCB0aXRsZSA9IHRpdGxlKSArCiAgICB0aGVtZV9idygpCiAgCiAgcmV0dXJuKGdncGxvdGx5KHApKQp9CgpjYWxjdWxhdGVQYWlyd2lzZURpc3RhbmNlc0FuZFBsb3REZW5zaXR5IDwtIGZ1bmN0aW9uKHF1ZXJ5X2RhdGEsIHJlZl9kYXRhLCBxdWVyeV9jZWxsX3R5cGVfY29sLCByZWZfY2VsbF90eXBlX2NvbCwgY2VsbF90eXBlX3F1ZXJ5LCBjZWxsX3R5cGVfcmVmZXJlbmNlLGRpc3RhbmNlX21ldHJpYywgY29ycmVsYXRpb25fbWV0aG9kID0gInBlYXJzb24iKSB7CiAgIyBTdWJzZXQgcXVlcnkgYW5kIHJlZmVyZW5jZSBkYXRhIHRvIHRoZSBzcGVjaWZpZWQgY2VsbCB0eXBlCiAgcXVlcnlfZGF0YV9zdWJzZXQgPC0gcXVlcnlfZGF0YVssICFpcy5uYShxdWVyeV9kYXRhW1txdWVyeV9jZWxsX3R5cGVfY29sXV0pICYgcXVlcnlfZGF0YVtbcXVlcnlfY2VsbF90eXBlX2NvbF1dID09IGNlbGxfdHlwZV9xdWVyeV0KICByZWZfZGF0YV9zdWJzZXQgPC0gcmVmX2RhdGFbLCAhaXMubmEocmVmX2RhdGFbW3JlZl9jZWxsX3R5cGVfY29sXV0pICYgcmVmX2RhdGFbW3JlZl9jZWxsX3R5cGVfY29sXV0gPT0gY2VsbF90eXBlX3JlZmVyZW5jZV0KICAKICAjIENvbnZlcnQgdG8gbWF0cml4CiAgcXVlcnlfbWF0IDwtIHQoYXMubWF0cml4KGFzc2F5KHF1ZXJ5X2RhdGFfc3Vic2V0LCAibG9nY291bnRzIikpKQogIHJlZl9tYXQgPC0gdChhcy5tYXRyaXgoYXNzYXkocmVmX2RhdGFfc3Vic2V0LCAibG9nY291bnRzIikpKQogIAogICMgQ29tYmluZSBxdWVyeSBhbmQgcmVmZXJlbmNlIG1hdHJpY2VzCiAgY29tYmluZWRfbWF0IDwtIHJiaW5kKHF1ZXJ5X21hdCwgcmVmX21hdCkKICAKICAjIENhbGN1bGF0ZSBwYWlyd2lzZSBkaXN0YW5jZXMgb3IgY29ycmVsYXRpb25zIGZvciBhbGwgY29tcGFyaXNvbnMKICBpZiAoZGlzdGFuY2VfbWV0cmljID09ICJjb3JyZWxhdGlvbiIpIHsKICAgIGlmIChjb3JyZWxhdGlvbl9tZXRob2QgPT0gInBlYXJzb24iKSB7CiAgICAgIGRpc3RfbWF0cml4IDwtIGNvcih0KGNvbWJpbmVkX21hdCksIG1ldGhvZCA9ICJwZWFyc29uIikKICAgIH0gZWxzZSBpZiAoY29ycmVsYXRpb25fbWV0aG9kID09ICJzcGVhcm1hbiIpIHsKICAgICAgZGlzdF9tYXRyaXggPC0gY29yKHQoY29tYmluZWRfbWF0KSwgbWV0aG9kID0gInNwZWFybWFuIikKICAgIH0gZWxzZSB7CiAgICAgIHN0b3AoIkludmFsaWQgY29ycmVsYXRpb24gbWV0aG9kLiBBdmFpbGFibGUgb3B0aW9uczogJ3BlYXJzb24nLCAnc3BlYXJtYW4nIikKICAgIH0KICB9IGVsc2UgewogICAgZGlzdF9tYXRyaXggPC0gZGlzdChjb21iaW5lZF9tYXQsIG1ldGhvZCA9IGRpc3RhbmNlX21ldHJpYykKICB9CiAgCiAgIyBDb252ZXJ0IGRpc3RfbWF0cml4IHRvIGEgc3F1YXJlIG1hdHJpeAogIGRpc3RfbWF0cml4IDwtIGFzLm1hdHJpeChkaXN0X21hdHJpeCkKICAKICAjIEV4dHJhY3QgdGhlIGRpc3RhbmNlcyBvciBjb3JyZWxhdGlvbnMgZm9yIHRoZSBkaWZmZXJlbnQgcGFpcndpc2UgY29tcGFyaXNvbnMKICBudW1fcXVlcnlfY2VsbHMgPC0gbnJvdyhxdWVyeV9tYXQpCiAgbnVtX3JlZl9jZWxscyA8LSBucm93KHJlZl9tYXQpCiAgZGlzdF9xdWVyeV9xdWVyeSA8LSBkaXN0X21hdHJpeFsxOm51bV9xdWVyeV9jZWxscywgMTpudW1fcXVlcnlfY2VsbHNdCiAgZGlzdF9yZWZfcmVmIDwtIGRpc3RfbWF0cml4WyhudW1fcXVlcnlfY2VsbHMrMSk6KG51bV9xdWVyeV9jZWxscytudW1fcmVmX2NlbGxzKSwgKG51bV9xdWVyeV9jZWxscysxKToobnVtX3F1ZXJ5X2NlbGxzK251bV9yZWZfY2VsbHMpXQogIGRpc3RfcXVlcnlfcmVmIDwtIGRpc3RfbWF0cml4WzE6bnVtX3F1ZXJ5X2NlbGxzLCAobnVtX3F1ZXJ5X2NlbGxzKzEpOihudW1fcXVlcnlfY2VsbHMrbnVtX3JlZl9jZWxscyldCiAgCiAgIyBDcmVhdGUgZGF0YSBmcmFtZSBmb3IgcGxvdHRpbmcKICBkaXN0X2RmIDwtIGRhdGEuZnJhbWUoCiAgICBDb21wYXJpc29uID0gYyhyZXAoIlF1ZXJ5IHZzIFF1ZXJ5IiwgbGVuZ3RoKGRpc3RfcXVlcnlfcXVlcnkpKSwKICAgICAgICAgICAgICAgICAgIHJlcCgiUmVmZXJlbmNlIHZzIFJlZmVyZW5jZSIsIGxlbmd0aChkaXN0X3JlZl9yZWYpKSwKICAgICAgICAgICAgICAgICAgIHJlcCgiUXVlcnkgdnMgUmVmZXJlbmNlIiwgbGVuZ3RoKGRpc3RfcXVlcnlfcmVmKSkpLAogICAgRGlzdGFuY2UgPSBjKGFzLnZlY3RvcihkaXN0X3F1ZXJ5X3F1ZXJ5KSwKICAgICAgICAgICAgICAgICBhcy52ZWN0b3IoZGlzdF9yZWZfcmVmKSwKICAgICAgICAgICAgICAgICBhcy52ZWN0b3IoZGlzdF9xdWVyeV9yZWYpKQogICkKICAKICAjIFBsb3QgZGVuc2l0eSBwbG90cwogIGdncGxvdChkaXN0X2RmLCBhZXMoeCA9IERpc3RhbmNlLCBjb2xvciA9IENvbXBhcmlzb24pKSArCiAgICBnZW9tX2RlbnNpdHkoKSArCiAgICBsYWJzKHggPSBpZmVsc2UoZGlzdGFuY2VfbWV0cmljID09ICJjb3JyZWxhdGlvbiIsIHBhc3RlKGNvcnJlbGF0aW9uX21ldGhvZCwgImNvcnJlbGF0aW9uIiksICJEaXN0YW5jZSIpLCB5ID0gIkRlbnNpdHkiLCB0aXRsZSA9ICJQYWlyd2lzZSBEaXN0YW5jZSBBbmFseXNpcyBhbmQgRGVuc2l0eSBWaXN1YWxpemF0aW9uIikgKwogICAgdGhlbWVfYncoKQp9CmBgYAoKIyBWaXN1YWxpemluZyBSZWdyZXNzaW9uIFJlc3VsdHMKCk5vdGU6IEhlcmUgb3JpZ2luYWwvb2JzZXJ2ZWQgcXVlcnkgZGF0YSBjZWxsIGxhYmVscyBhcmUgdXNlZC4KCldlIHZpc3VhbGl6ZSB0aGUgb3V0Y29tZSBvZiB0aGUgcmVncmVzc2lvbiBhbmFseXNpcyBieSBjcmVhdGluZyBsaW5lIHBsb3RzIHRoYXQgZGVwaWN0IHRoZSBSLXNxdWFyZWQgdmFsdWVzIGZvciBlYWNoIHByaW5jaXBhbCBjb21wb25lbnQuIAoKUEMxOiBUaGUgaGlnaCBSLXNxdWFyZWQgdmFsdWUgaW5kaWNhdGVzIHRoYXQgYSBzaWduaWZpY2FudCBwb3J0aW9uIG9mIHRoZSB2YXJpYWJpbGl0eSBpbiBQQzEgaXMgZXhwbGFpbmVkIGJ5IHRoZSBjZWxsIGxhYmVscy4gVGhpcyBzdWdnZXN0cyB0aGF0IFBDMSBjYXB0dXJlcyBtZWFuaW5nZnVsIGRpZmZlcmVuY2VzIGJldHdlZW4gdGhlIGNlbGwgdHlwZXMuCgpQQzI6IENhcHR1cmVzIGEgc3Vic3RhbnRpYWwgYW1vdW50IG9mIHZhcmlhdGlvbiByZWxhdGVkIHRvIGNlbGwgbGFiZWxzLiBUaGlzIGNvbXBvbmVudCBjb250cmlidXRlcyBzaWduaWZpY2FudGx5IHRvIGRpc3Rpbmd1aXNoaW5nIGJldHdlZW4gZGlmZmVyZW50IGNlbGwgdHlwZXMuCgpQQzM6IFRoZSBSLXNxdWFyZWQgdmFsdWUgb2YgUEMzIGluZGljYXRlcyB0aGF0IGl0IHN0aWxsIGNhcHR1cmVzIGEgbW9kZXJhdGUgYW1vdW50IG9mIHZhcmlhdGlvbiBleHBsYWluZWQgYnkgY2VsbCBsYWJlbHMsIGFsdGhvdWdoIGl0IGlzIGxlc3MgaW5mbHVlbnRpYWwgdGhhbiBQQzEgYW5kIFBDMi4KClBDNCB0byBQQzEwOiBUaGUgUi1zcXVhcmVkIHZhbHVlcyBmb3IgUEM0IHRvIFBDMTAgYXJlIHJlbGF0aXZlbHkgbG93ZXIsIHJhbmdpbmcgZnJvbSAwLjAzNjYgdG8gMC4wMDczLiBUaGVzZSBjb21wb25lbnRzIGNhcHR1cmUgbXVjaCBsZXNzIG9mIHRoZSB2YXJpYXRpb24gZXhwbGFpbmVkIGJ5IHRoZSBjZWxsIGxhYmVscy4gVGhlaXIgbG93IFItc3F1YXJlZCB2YWx1ZXMgbWlnaHQgc3VnZ2VzdCB0aGF0IHRoZXNlIHByaW5jaXBhbCBjb21wb25lbnRzIG1pZ2h0IGJlIGluZmx1ZW5jZWQgYnkgb3RoZXIgZmFjdG9ycyBub3QgYWNjb3VudGVkIGZvciBieSB0aGUgcHJvdmlkZWQgY2VsbCBsYWJlbHMKCmBgYHtyIFIyIGFuYWx5c2lzLCBlY2hvPVQsIHdhcm5pbmc9Rn0KIyBEYXRhIHByZXBhcmF0aW9uCnF1ZXJ5X29ic2VydmVkIDwtIGRhdGEuZnJhbWUocmVkdWNlZERpbShxdWVyeSwgIlBDQSIpLCBDZWxsVHlwZXMgPSBxdWVyeSRsYWJlbCkKcnNxdWFyZWRfZGYgPC0gcmVncmVzc19QQ3MocXVlcnlfb2JzZXJ2ZWQpCgojIENyZWF0ZSBhIGxpbmUgcGxvdCB1c2luZyBnZ3Bsb3QKZ2dwbG90KHJzcXVhcmVkX2RmLCBhZXMoeCA9IFBDLCB5ID0gUjIpKSArCiAgZ2VvbV9saW5lKCkgKwogIGdlb21fcG9pbnQoc2hhcGUgPSAxNikgKwogIGxhYnMoeCA9ICJQcmluY2lwYWwgQ29tcG9uZW50IChQQykiLAogICAgICAgeSA9ICJSLXNxdWFyZWQiLAogICAgICAgdGl0bGUgPSAiUi1zcXVhcmVkIGZvciBQcmluY2lwYWwgQ29tcG9uZW50cyIpICsKICB5bGltKDAsIDEpICsKICB0aGVtZV9idygpICsgCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IDE6MTAsIGxhYmVscyA9IDE6MTApCmBgYAoKIyBTY2F0dGVyIHBsb3RzIGJldHdlZW4gZGlmZmVyZW50IFBDcyBmb3IgcXVlcnkgZGF0YXNldCAoT2JzZXJ2ZWQgcXVlcnkgZGF0YXNldCkKCmBgYHtyIHNjYXR0ZXIgcGxvdHMgcXVlcnkgb2JzZXJ2ZWQsIGVjaG89VCwgd2FybmluZz1GfQoKIyBEZWZpbmUgY29sb3IgcGFsZXR0ZQpzZWVkcyA8LSBjKCIjRkYwMDAwRkYiLCAiI0NDRkYwMEZGIiwgIiMwMEZGNjZGRiIsICIjMDA2NkZGRkYiLCAiI0NDMDBGRkZGIikKY29sb3JfcGFsZXR0ZSA8LSBjcmVhdGVQYWxldHRlKGxlbmd0aCh1bmlxdWUocXVlcnlfb2JzZXJ2ZWQkQ2VsbFR5cGUpKSwgc2VlZHMpCm5hbWVzKGNvbG9yX3BhbGV0dGUpIDwtIHVuaXF1ZShxdWVyeV9vYnNlcnZlZCRDZWxsVHlwZSkKYGBgCgojIyBQQzEgdnMgUEMyIHNjYXR0ZXIgcGxvdAoKVGhlIHNjYXR0ZXIgcGxvdCBvZiBQQzEgdnMgUEMyIGluZGljYXRlcyB0aGF0IHRoZXJlIGFyZSBzZXBhcmF0ZSBjbHVzdGVycyBmb3IgTksgY2VsbHMgYW5kIENEMTQgY2VsbHMsIHdoaWNoIG1lYW5zIHRoYXQgdGhlc2UgdHdvIGNlbGwgdHlwZXMgYXJlIHdlbGwtc2VwYXJhdGVkIGZyb20gdGhlIG90aGVycyBpbiB0aGlzIHR3by1kaW1lbnNpb25hbCBzcGFjZSBkZWZpbmVkIGJ5IFBDMSBhbmQgUEMyLiBUaGlzIHNlcGFyYXRpb24gc3VnZ2VzdHMgdGhhdCBQQzEgYW5kIFBDMiBjYXB0dXJlIGRpc3RpbmN0IHZhcmlhdGlvbnMgdGhhdCBhbGxvdyBmb3IgZGlzdGluZ3Vpc2hpbmcgYmV0d2VlbiBOSyBjZWxscyBhbmQgQ0QxNCBjZWxscyBmcm9tIG90aGVyIGNlbGwgdHlwZXMuCgpgYGB7ciBzY2F0dGVyIHBsb3RzIHF1ZXJ5IG9ic2VydmVkIFBDMSB2cyBQQzIsIGVjaG89VCwgd2FybmluZz1GfQpzY2F0dGVyX3RvX3Bsb3RseShxdWVyeV9vYnNlcnZlZCwgIlBDMSIsICJQQzIiLCAiQ2VsbFR5cGVzIiwgIlBDMSB2cyBQQzIiKQpgYGAKCiMjIFBDMSB2cyBQQzMgc2NhdHRlciBwbG90CgpUaGUgdmFyaWF0aW9uIGNhcHR1cmVkIGJ5IFBDMyBjb250cmlidXRlcyB0byB0aGUgc2VwYXJhdGlvbiBvZiBDRDE0IGNlbGxzIGZyb20gb3RoZXIgY2VsbCB0eXBlcyB3aGVuIGxvb2tpbmcgYXQgdGhlIHBsb3Qgd2l0aCBQQzMuCgpgYGB7ciBzY2F0dGVyIHBsb3RzIHF1ZXJ5IG9ic2VydmVkIFBDMSB2cyBQQzMsIGVjaG89VH0Kc2NhdHRlcl90b19wbG90bHkocXVlcnlfb2JzZXJ2ZWQsICJQQzMiLCAiUEMxIiwgIkNlbGxUeXBlcyIsICJQQzEgdnMgUEMzIikKYGBgCgojIyBQQzEgdnMgUEM0IHNjYXR0ZXIgcGxvdAoKU2ltaWxhciB0byBhYm92ZSByZXN1bHRzLCB0aGUgdmFyaWF0aW9uIGNhcHR1cmVkIGJ5IFBDNCBjb250cmlidXRlcyB0byB0aGUgc2VwYXJhdGlvbiBvZiBDRDE0IGNlbGxzIGZyb20gb3RoZXIgY2VsbCB0eXBlcy4KCmBgYHtyIHNjYXR0ZXIgcGxvdHMgcXVlcnkgb2JzZXJ2ZWQgUEMxIHZzIFBDNCwgZWNobz1UfQpzY2F0dGVyX3RvX3Bsb3RseShxdWVyeV9vYnNlcnZlZCwgIlBDNCIsICJQQzEiLCAiQ2VsbFR5cGVzIiwgIlBDMSB2cyBQQzQiKQpgYGAKCiMjIFBDNCB2cyBQQzUgc2NhdHRlciBwbG90CgpQbG90IG9mIFBDNCB2cyBQQzUgc2hvd3MgYSBtaXhlZCBwYXR0ZXJuIHdpdGggbm8gY2xlYXIgc2VwYXJhdGlvbiBvciBjbHVzdGVyaW5nIG9mIGNlbGwgdHlwZXMsIHN1Z2dlc3RpbmcgdGhhdCB0aGUgdmFyaWF0aW9uIGNhcHR1cmVkIGJ5IHRoZXNlIFBDcyBtYXkgbm90IGhhdmUgYSBzdHJvbmcgZGlzY3JpbWluYXRvcnkgZWZmZWN0IG9uIHRoZSBkaWZmZXJlbnQgY2VsbCB0eXBlcyBpbiB0aGUgZGF0YXNldC4gCgpgYGB7ciBzY2F0dGVyIHBsb3RzIHF1ZXJ5IG9ic2VydmVkIFBDNCB2cyBQQzUsIGVjaG89VH0Kc2NhdHRlcl90b19wbG90bHkocXVlcnlfb2JzZXJ2ZWQsICJQQzQiLCAiUEM1IiwgIkNlbGxUeXBlcyIsICJQQzQgdnMgUEM1IikKYGBgCgojIyBCb3hwbG90cyBvZiBQQzEgdnMgQ2VsbCB0eXBlcwoKQ0QxNCBjZWxscyBtaWdodCBleGhpYml0IGRpc3RpbmN0IG1vbGVjdWxhciBjaGFyYWN0ZXJpc3RpY3MgdGhhdCBzZXQgdGhlbSBhcGFydCBmcm9tIHRoZSBvdGhlciB0aHJlZSBjZWxsIHR5cGVzLgoKYGBge3IgUEMxIHZzIGNsdXN0ZXIgYm94cGxvdHMgcXVlcnkgb2JzZXJ2ZWQsIGVjaG89VH0KZ2dwbG90KHF1ZXJ5X29ic2VydmVkLCBhZXMoeCA9IENlbGxUeXBlcywgeSA9IFBDMSwgZmlsbCA9IENlbGxUeXBlcykpICsKICAgIGdlb21fYm94cGxvdCgpICsKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkgKwogICAgZ3VpZGVzKGZpbGwgPSAibm9uZSIpICsKICAgIHhsYWIoIkNlbGxUeXBlcyIpICsKICAgIHlsYWIoIlBDMSIpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAicmVkIikKYGBgCgojIyBCb3hwbG90cyBvZiBQQzIgdnMgQ2VsbCB0eXBlcwoKVGhlc2UgcmVzdWx0cyBpbmRpY2F0ZSB0aGF0IE5LIGNlbGxzIG1pZ2h0IGV4aGliaXQgZGlzdGluY3QgZ2VuZSBleHByZXNzaW9uIHBhdHRlcm5zIG9yIG1vbGVjdWxhciBjaGFyYWN0ZXJpc3RpY3MgY2FwdHVyZWQgYnkgUEMyLgoKYGBge3IgUEMyIHZzIGNsdXN0ZXIgYm94cGxvdHMgcXVlcnkgb2JzZXJ2ZWQsIGVjaG89VH0KZ2dwbG90KHF1ZXJ5X29ic2VydmVkLCBhZXMoeCA9IENlbGxUeXBlcywgeSA9IFBDMiwgZmlsbCA9IENlbGxUeXBlcykpICsKICAgIGdlb21fYm94cGxvdCgpICsKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkgKwogICAgZ3VpZGVzKGZpbGwgPSAibm9uZSIpICsKICAgIHhsYWIoIkNlbGxUeXBlcyIpICsKICAgIHlsYWIoIlBDMiIpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAicmVkIikKYGBgCgojIyBCb3hwbG90cyBvZiBQQzMgdnMgQ2VsbCB0eXBlcwoKYGBge3IgUEMzIHZzIGNsdXN0ZXIgYm94cGxvdHMgcXVlcnkgb2JzZXJ2ZWQsIGVjaG89VH0KZ2dwbG90KHF1ZXJ5X29ic2VydmVkLCBhZXMoeCA9IENlbGxUeXBlcywgeSA9IFBDMywgZmlsbCA9IENlbGxUeXBlcykpICsKICAgIGdlb21fYm94cGxvdCgpICsKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkgKwogICAgZ3VpZGVzKGZpbGwgPSAibm9uZSIpICsKICAgIHhsYWIoIkNlbGxUeXBlcyIpICsKICAgIHlsYWIoIlBDMyIpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAicmVkIikKYGBgCgojIFF1ZXJ5IGRhdGFzZXQgd2hlbiBDRDQgY2VsbCB0eXBlIGlzIHJlbW92ZWQgZnJvbSByZWZlcmVuY2UgZGF0YXNldAoKSW4gdGhpcyBzZWN0aW9uLCB3ZSBmb2N1cyBvbiB0aGUgcXVlcnkgZGF0YXNldCB0aGF0IHdhcyBnZW5lcmF0ZWQgYWZ0ZXIgcmVtb3ZpbmcgQ0Q0IGNlbGwgdHlwZXMgZnJvbSB0aGUgcmVmZXJlbmNlIGRhdGFzZXQuIFdlIHBlcmZvcm0gYW5hbHlzaXMgb24gdGhpcyBtb2RpZmllZCBkYXRhc2V0IHRvIGV4cGxvcmUgaG93IHRoZSBQcmluY2lwYWwgQ29tcG9uZW50cyAoUENzKSByZWxhdGUgdG8gdGhlIHByZWRpY3RlZCBjZWxsIGxhYmVscy4KIApQQzEgY2FwdHVyZXMgYSBoaWdoIGFtb3VudCBvZiB2YXJpYW5jZSwgc3VnZ2VzdGluZyB0aGF0IGl0IGV4cGxhaW5zIGEgc3Vic3RhbnRpYWwgcG9ydGlvbiBvZiB0aGUgdmFyaWFiaWxpdHkgaW4gdGhlIGRhdGEuCgpQQzIgYWxzbyBjYXB0dXJlcyBhIHNpZ25pZmljYW50IGFtb3VudCBvZiB2YXJpYW5jZSwgaW5kaWNhdGluZyBpdHMgaW1wb3J0YW5jZSBpbiBleHBsYWluaW5nIHZhcmlhYmlsaXR5LgoKVGhlIFItc3F1YXJlZCB2YWx1ZXMgZm9yIFBDMyB0byBQQzEwIGFyZSBtdWNoIGxvd2VyLCBpbmRpY2F0aW5nIHRoYXQgdGhlc2UgY29tcG9uZW50cyBjYXB0dXJlIHJlbGF0aXZlbHkgbGVzcyB2YXJpYW5jZSBpbiB0aGUgZGF0YS4KCmBgYHtyIFIyIHF1ZXJ5IChDRDQgcmVtdm92ZWQgZnJvbSByZWZlcmVuY2UpLCBlY2hvPVR9CiMgRGF0YSBwcmVwYXJhdGlvbgpxdWVyeTEgPC0gZGF0YS5mcmFtZShyZWR1Y2VkRGltKHF1ZXJ5LCAiUENBIiksIENlbGxUeXBlcyA9IHRhYltbMV1dJGFubm90YXRpb25zJGxhYmVscykKcnNxdWFyZWRfZGYgPC0gcmVncmVzc19QQ3MocXVlcnkxKQoKIyBDcmVhdGUgYSBsaW5lIHBsb3QgdXNpbmcgZ2dwbG90CmdncGxvdChyc3F1YXJlZF9kZiwgYWVzKHggPSBQQywgeSA9IFIyKSkgKwogIGdlb21fbGluZSgpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMTYpICsKICBsYWJzKHggPSAiUHJpbmNpcGFsIENvbXBvbmVudCAoUEMpIiwKICAgICAgIHkgPSAiUi1zcXVhcmVkIiwKICAgICAgIHRpdGxlID0gIlItc3F1YXJlZCBmb3IgUHJpbmNpcGFsIENvbXBvbmVudHMgKENENCBjZWxscyByZW1vdmVkIGZyb20gcmVmZXJlbmNlIGRhdGFzZXQpIikgKwogIHlsaW0oMCwgMSkgKwogIHRoZW1lX2J3KCkgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gMToxMCwgbGFiZWxzID0gMToxMCkKYGBgCgojIFNjYXR0ZXIgcGxvdHMgYmV0d2VlbiBkaWZmZXJlbnQgUENzIGZvciBxdWVyeSBkYXRhc2V0IChmcm9tIHJlZmVyZW5jZSBDRDQgY2VsbHMgcmVtb3ZlZCkKCldlIGNyZWF0ZSBzY2F0dGVyIHBsb3RzIHRvIHZpc3VhbGl6ZSB0aGUgUENBIHJlc3VsdHMgZm9yIHRoZSBxdWVyeSBkYXRhc2V0IHdpdGggQ0Q0IGNlbGwgdHlwZXMgcmVtb3ZlZCBmcm9tIHRoZSByZWZlcmVuY2UuCgpgYGB7ciBTYWN0dGVyIHBsb3RzIHF1ZXJ5IChDRDQgcmVtdm92ZWQgZnJvbSByZWZlcmVuY2UpLCBlY2hvPVR9CiMgRGVmaW5lIGNvbG9yIHBhbGV0dGUKc2VlZHMgPC0gYygiI0ZGMDAwMEZGIiwgIiNDQ0ZGMDBGRiIsICIjMDBGRjY2RkYiLCAiIzAwNjZGRkZGIiwgIiNDQzAwRkZGRiIpCmNvbG9yX3BhbGV0dGUgPC0gY3JlYXRlUGFsZXR0ZShsZW5ndGgodW5pcXVlKHF1ZXJ5MSRDZWxsVHlwZSkpLCBzZWVkcykKbmFtZXMoY29sb3JfcGFsZXR0ZSkgPC0gdW5pcXVlKHF1ZXJ5MSRDZWxsVHlwZSkKYGBgCgojIyBQQzEgdnMgUEMyIHNjYXR0ZXIgcGxvdAoKVGhlIHNjYXR0ZXIgcGxvdCBvZiBQQzEgdnMgUEMyIGZvciB0aGUgcXVlcnkgZGF0YXNldCB3aXRoIENENCBjZWxsIHR5cGVzIHJlbW92ZWQgZnJvbSB0aGUgcmVmZXJlbmNlIGRlbW9uc3RyYXRlcyBhIGRpc3RpbmN0IHNlcGFyYXRpb24gb2YgY2x1c3RlcnMuIFRoaXMgc2VwYXJhdGlvbiBzdWdnZXN0cyB0aGF0IHRoZSB2YXJpYXRpb25zIGNhcHR1cmVkIGJ5IFBDMSBhbmQgUEMyIGFyZSBlZmZlY3RpdmUgYXQgZGlzdGluZ3Vpc2hpbmcgZGlmZmVyZW50IGNlbGwgdHlwZXMgaW4gdGhlIHF1ZXJ5IGRhdGFzZXQuCgpgYGB7ciBTYWN0dGVyIHBsb3RzIHF1ZXJ5IChDRDQgcmVtdm92ZWQgZnJvbSByZWZlcmVuY2UpIFBDMSB2cyBQQzIsIGVjaG89VH0Kc2NhdHRlcl90b19wbG90bHkocXVlcnkxLCAiUEMxIiwgIlBDMiIsICJDZWxsVHlwZXMiLCAiUEMxIHZzIFBDMiIpCmBgYAoKIyMgUEMxIHZzIFBDMyBzY2F0dGVyIHBsb3QKClRoZSBzZXBhcmF0aW9uIG9mIENEMTQgY2VsbHMgZnJvbSB0aGUgb3RoZXJzIGFsb25nIHRoZSBQQzMgYXhpcyBpcyBub3RhYmxlLCBpbmRpY2F0aW5nIHRoYXQgdGhlIHZhcmlhdGlvbiBjYXB0dXJlZCBieSBQQzMgY29udHJpYnV0ZXMgc2lnbmlmaWNhbnRseSB0byBkaXN0aW5ndWlzaGluZyBDRDE0IGNlbGxzIGZyb20gdGhlIHJlc3QuIEFkZGl0aW9uYWxseSwgdGhlIHByb3hpbWl0eSBvZiBDRDggYW5kIE5LIGNlbGxzIGFsb25nIHRoZSBQQzMgYXhpcyBzdWdnZXN0cyB0aGF0IHRoZXNlIGNlbGwgdHlwZXMgbWF5IHNoYXJlIHNvbWUgY29tbW9uIGdlbmUgZXhwcmVzc2lvbiBwYXR0ZXJucyBvciBtb2xlY3VsYXIgY2hhcmFjdGVyaXN0aWNzIGNhcHR1cmVkIGJ5IFBDMy4gCgpBbHNvLCBjb25jb3JkYW5jZSBwbG90IGFib3ZlIHJldmVhbGVkIHRoYXQgd2hlbiBDRDggY2VsbHMgd2VyZSByZW1vdmVkIGZyb20gdGhlIHJlZmVyZW5jZSBkYXRhc2V0LCBhIHNtYWxsIHN1YnNldCBvZiBjZWxscyBpbiB0aGUgcXVlcnkgZGF0YXNldCB3ZXJlIGJlaW5nIGFzc2lnbmVkIGFzIE5LIGNlbGxzLgoKYGBge3IgU2FjdHRlciBwbG90cyBxdWVyeSAoQ0Q0IHJlbXZvdmVkIGZyb20gcmVmZXJlbmNlKSBQQzEgdnMgUEMzLCBlY2hvPVR9CnNjYXR0ZXJfdG9fcGxvdGx5KHF1ZXJ5MSwgIlBDMyIsICJQQzEiLCAiQ2VsbFR5cGVzIiwgIlBDMSB2cyBQQzMiKQpgYGAKCiMjIFBDMiB2cyBQQzMgc2NhdHRlciBwbG90CgpTZXBhcmF0aW9uIG9mIE5LIGNlbGxzIGZyb20gb3RoZXIgY2VsbCB0eXBlcyBzZWVtcyB0byBiZSBpbmZsdWVuY2VkIGJ5IGJvdGggUEMyIGFuZCBQQzMsCgpgYGB7ciBTYWN0dGVyIHBsb3RzIHF1ZXJ5IChDRDQgcmVtdm92ZWQgZnJvbSByZWZlcmVuY2UpIFBDMiB2cyBQQzMsIGVjaG89VH0Kc2NhdHRlcl90b19wbG90bHkocXVlcnkxLCAiUEMzIiwgIlBDMiIsICJDZWxsVHlwZXMiLCAiUEMzIHZzIFBDMiIpCmBgYAoKIyMgQm94cGxvdHMgb2YgUEMxIHZzIENlbGwgdHlwZXMKCmBgYHtyIFBDMSB2cyBjbHVzdGVyIGJveHBsb3RzIHF1ZXJ5MSwgZWNobz1UfQpnZ3Bsb3QocXVlcnkxLCBhZXMoeCA9IENlbGxUeXBlcywgeSA9IFBDMSwgZmlsbCA9IENlbGxUeXBlcykpICsKICAgIGdlb21fYm94cGxvdCgpICsKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkgKwogICAgZ3VpZGVzKGZpbGwgPSAibm9uZSIpICsKICAgIHhsYWIoIkNlbGxUeXBlcyIpICsKICAgIHlsYWIoIlBDMSIpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAicmVkIikKYGBgCgojIyBCb3hwbG90cyBvZiBQQzIgdnMgQ2VsbCB0eXBlcwoKYGBge3IgUEMyIHZzIGNsdXN0ZXIgYm94cGxvdHMgcXVlcnkxLCBlY2hvPVR9CmdncGxvdChxdWVyeTEsIGFlcyh4ID0gQ2VsbFR5cGVzLCB5ID0gUEMxLCBmaWxsID0gQ2VsbFR5cGVzKSkgKwogICAgZ2VvbV9ib3hwbG90KCkgKwogICAgdGhlbWVfYncoKSArCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSArCiAgICBndWlkZXMoZmlsbCA9ICJub25lIikgKwogICAgeGxhYigiQ2VsbFR5cGVzIikgKwogICAgeWxhYigiUEMyIikgKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJyZWQiKQpgYGAKCiMjIEJveHBsb3RzIG9mIFBDMyB2cyBDZWxsIHR5cGVzCgpgYGB7ciBQMyB2cyBjbHVzdGVyIGJveHBsb3RzIHF1ZXJ5MSwgZWNobz1UfQpnZ3Bsb3QocXVlcnkxLCBhZXMoeCA9IENlbGxUeXBlcywgeSA9IFBDMSwgZmlsbCA9IENlbGxUeXBlcykpICsKICAgIGdlb21fYm94cGxvdCgpICsKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkgKwogICAgZ3VpZGVzKGZpbGwgPSAibm9uZSIpICsKICAgIHhsYWIoIkNlbGxUeXBlcyIpICsKICAgIHlsYWIoIlBDMyIpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAicmVkIikKYGBgCgojIFF1ZXJ5IGRhdGFzZXQgd2hlbiBDRDE0IGNlbGwgdHlwZSBpcyByZW1vdmVkIGZyb20gcmVmZXJlbmNlIGRhdGFzZXQKCkluIHRoaXMgc2VjdGlvbiwgd2UgZm9jdXMgb24gdGhlIHF1ZXJ5IGRhdGFzZXQgdGhhdCB3YXMgZ2VuZXJhdGVkIGFmdGVyIHJlbW92aW5nIENEMTQgY2VsbCB0eXBlcyBmcm9tIHRoZSByZWZlcmVuY2UgZGF0YXNldC4gV2UgcGVyZm9ybSBhbmFseXNpcyBvbiB0aGlzIG1vZGlmaWVkIGRhdGFzZXQgdG8gZXhwbG9yZSBob3cgdGhlIFByaW5jaXBhbCBDb21wb25lbnRzIChQQ3MpIGRlcml2ZWQgZnJvbSBQQ0EgcmVsYXRlIHRvIHRoZSBwcmVkaWN0ZWQgY2VsbCBsYWJlbHMuCgpQQzEgZXhwbGFpbnMgYXBwcm94aW1hdGVseSAxMS4wNiUgb2YgdGhlIHRvdGFsIHZhcmlhbmNlIGluIHRoZSBkYXRhLgpUaGlzIHZhbHVlIHN1Z2dlc3RzIHRoYXQgUEMxIGNhcHR1cmVzIGEgbW9kZXJhdGUgYW1vdW50IG9mIHZhcmlhdGlvbiBpbiB0aGUgZGF0YXNldC4gV2hpbGUgbm90IGV4dHJlbWVseSBoaWdoLCBpdCBzdGlsbCBjb250cmlidXRlcyBzaWduaWZpY2FudGx5IHRvIHRoZSB1bmRlcnN0YW5kaW5nIG9mIHRoZSBkaWZmZXJlbmNlcyBhbW9uZyB0aGUgZGF0YSBwb2ludHMuCgpQQzIgZXhwbGFpbnMgYXBwcm94aW1hdGVseSA4Ni4xMCUgb2YgdGhlIHRvdGFsIHZhcmlhbmNlIGluIHRoZSBkYXRhLgpUaGlzIGhpZ2ggUi1zcXVhcmVkIHZhbHVlIGluZGljYXRlcyB0aGF0IFBDMiBjYXB0dXJlcyBhIHN1YnN0YW50aWFsIGFtb3VudCBvZiB2YXJpYXRpb24gaW4gdGhlIGRhdGFzZXQuIFBDMiBpcyBhIGRvbWluYW50IGNvbXBvbmVudCBpbiBleHBsYWluaW5nIHRoZSBkaWZmZXJlbmNlcyBhbW9uZyB0aGUgZGF0YSBwb2ludHMuCgpQQzMgZXhwbGFpbnMgYXBwcm94aW1hdGVseSA0NC4xNyUgb2YgdGhlIHRvdGFsIHZhcmlhbmNlIGluIHRoZSBkYXRhLgpUaGlzIHZhbHVlIGluZGljYXRlcyB0aGF0IFBDMyBjYXB0dXJlcyBhIG1vZGVyYXRlIHRvIGhpZ2ggYW1vdW50IG9mIHZhcmlhdGlvbiBpbiB0aGUgZGF0YXNldC4KClBDNCB0byBQQzEwIGVhY2ggZXhwbGFpbiBsZXNzIHRoYW4gMTAlIG9mIHRoZSB0b3RhbCB2YXJpYW5jZSBpbiB0aGUgZGF0YS4KVGhlc2UgY29tcG9uZW50cyBjb250cmlidXRlIHJlbGF0aXZlbHkgbGl0dGxlIHRvIHRoZSBvdmVyYWxsIHZhcmlhbmNlIGFuZCBtaWdodCBjYXB0dXJlIG5vaXNlIG9yIGxlc3Mgc2lnbmlmaWNhbnQgcGF0dGVybnMgaW4gdGhlIGRhdGFzZXQuCgpgYGB7ciBSMiBxdWVyeSAoQ0QxNCByZW12b3ZlZCBmcm9tIHJlZmVyZW5jZSksIGVjaG89VH0KCiMgRGF0YSBwcmVwYXJhdGlvbgpxdWVyeTIgPC0gZGF0YS5mcmFtZShyZWR1Y2VkRGltKHF1ZXJ5LCAiUENBIiksIENlbGxUeXBlcyA9IHRhYltbMl1dJGFubm90YXRpb25zJGxhYmVscykKcnNxdWFyZWRfZGYgPC0gcmVncmVzc19QQ3MocXVlcnkyKQoKIyBDcmVhdGUgYSBsaW5lIHBsb3QgdXNpbmcgZ2dwbG90CmdncGxvdChyc3F1YXJlZF9kZiwgYWVzKHggPSBQQywgeSA9IFIyKSkgKwogIGdlb21fbGluZSgpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMTYpICsKICBsYWJzKHggPSAiUHJpbmNpcGFsIENvbXBvbmVudCAoUEMpIiwKICAgICAgIHkgPSAiUi1zcXVhcmVkIiwKICAgICAgIHRpdGxlID0gIlItc3F1YXJlZCBmb3IgUHJpbmNpcGFsIENvbXBvbmVudHMgKENEMTQgY2VsbHMgcmVtb3ZlZCBmcm9tIHJlZmVyZW5jZSBkYXRhc2V0KSIpICsKICB5bGltKDAsIDEpICsKICB0aGVtZV9idygpICsgCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcyA9IDE6MTAsIGxhYmVscyA9IDE6MTApCmBgYAoKIyBTY2F0dGVyIHBsb3RzIGJldHdlZW4gZGlmZmVyZW50IFBDcyBmb3IgcXVlcnkgZGF0YXNldCAoZnJvbSByZWZlcmVuY2UgQ0QxNCBjZWxscyByZW1vdmVkKQoKV2UgY3JlYXRlIHNjYXR0ZXIgcGxvdHMgdG8gdmlzdWFsaXplIHRoZSBQQ0EgcmVzdWx0cyBmb3IgdGhlIHF1ZXJ5IGRhdGFzZXQgd2l0aCBDRDE0IGNlbGwgdHlwZXMgcmVtb3ZlZCBmcm9tIHRoZSByZWZlcmVuY2UuCgpgYGB7ciBTYWN0dGVyIHBsb3RzIHF1ZXJ5IChDRDE0IHJlbXZvdmVkIGZyb20gcmVmZXJlbmNlKSwgZWNobz1UfQojIERlZmluZSBjb2xvciBwYWxldHRlCnNlZWRzIDwtIGMoIiNGRjAwMDBGRiIsICIjQ0NGRjAwRkYiLCAiIzAwRkY2NkZGIiwgIiMwMDY2RkZGRiIsICIjQ0MwMEZGRkYiKQpjb2xvcl9wYWxldHRlIDwtIGNyZWF0ZVBhbGV0dGUobGVuZ3RoKHVuaXF1ZShxdWVyeTIkQ2VsbFR5cGUpKSwgc2VlZHMpCm5hbWVzKGNvbG9yX3BhbGV0dGUpIDwtIHVuaXF1ZShxdWVyeTIkQ2VsbFR5cGUpCmBgYAoKIyMgUEMxIHZzIFBDMiBzY2F0dGVyIHBsb3QKCkluIHRoZSBzY2F0dGVyIHBsb3Qgb2YgUEMxIHZzIFBDMiBmb3IgdGhlIHF1ZXJ5IGRhdGFzZXQgKHdpdGggcmVmZXJlbmNlIENEMTQgY2VsbHMgcmVtb3ZlZCksIHRoZSBmb2xsb3dpbmcgb2JzZXJ2YXRpb25zIGNhbiBiZSBtYWRlOgoKVHdvIFBvcHVsYXRpb25zL0NsdXN0ZXJzIG9mIENEOCBDZWxsczogVGhlcmUgYXJlIHR3byBkaXN0aW5jdCBjbHVzdGVycyBvciBwb3B1bGF0aW9ucyBvZiBDRDggY2VsbHMgdmlzaWJsZSBvbiB0aGUgcGxvdC4gT25lIG9mIHRoZXNlIGNsdXN0ZXJzIG92ZXJsYXBzIHdpdGggQ0Q0IGNlbGxzLCBpbmRpY2F0aW5nIHNvbWUgZGVncmVlIG9mIHNpbWlsYXJpdHkgaW4gdGhlaXIgZ2VuZSBleHByZXNzaW9uIHBhdHRlcm5zLgoKTksgY2VsbHMgYXJlIHdlbGwtc2VwYXJhdGVkIGZyb20gdGhlIG90aGVyIGNlbGwgdHlwZXMsIHN1Z2dlc3RpbmcgdGhhdCB0aGUgdmFyaWF0aW9uIGNhcHR1cmVkIGJ5IFBDMSBhbmQgUEMyIGlzIGVmZmVjdGl2ZSBpbiBkaXN0aW5ndWlzaGluZyBOSyBjZWxscyBmcm9tIHRoZSByZXN0LgoKYGBge3IgU2FjdHRlciBwbG90cyBxdWVyeSAoQ0QxNCByZW12b3ZlZCBmcm9tIHJlZmVyZW5jZSkgUEMxIHZzIFBDMiwgZWNobz1UfQpzY2F0dGVyX3RvX3Bsb3RseShxdWVyeTIsICJQQzEiLCAiUEMyIiwgIkNlbGxUeXBlcyIsICJQQzEgdnMgUEMyIikKYGBgCgojIyBQQzEgdnMgUEM0IHNjYXR0ZXIgcGxvdAoKYGBge3IgU2FjdHRlciBwbG90cyBxdWVyeSAoQ0QxNCByZW12b3ZlZCBmcm9tIHJlZmVyZW5jZSkgUEMxIHZzIFBDNCwgZWNobz1UfQpzY2F0dGVyX3RvX3Bsb3RseShxdWVyeTIsICJQQzQiLCAiUEMxIiwgIkNlbGxUeXBlcyIsICJQQzEgdnMgUEM0IikKYGBgCgojIyBQQzIgdnMgUEM0IHNjYXR0ZXIgcGxvdAoKYGBge3IgU2FjdHRlciBwbG90cyBxdWVyeSAoQ0QxNCByZW12b3ZlZCBmcm9tIHJlZmVyZW5jZSkgUEMyIHZzIFBDNCwgZWNobz1UfQpzY2F0dGVyX3RvX3Bsb3RseShxdWVyeTIsICJQQzQiLCAiUEMyIiwgIkNlbGxUeXBlcyIsICJQQzQgdnMgUEMyIikKYGBgCgojIyBCb3hwbG90cyBvZiBQQzEgdnMgQ2VsbCB0eXBlcwoKVGhlIGJveHBsb3RzIG9mIFBDMSB2YWx1ZXMgZm9yIGRpZmZlcmVudCBjZWxsIHR5cGVzIHJldmVhbCB0aGF0IHRoZSBDRDggcG9wdWxhdGlvbiBleGhpYml0cyBhIGxhcmdlciBzcHJlYWQgb3IgdmFyaWFiaWxpdHkgYWxvbmcgdGhlIFBDMSBheGlzIGNvbXBhcmVkIHRvIHRoZSBDRDQgYW5kIE5LIHBvcHVsYXRpb25zLiBUaGlzIHN1Z2dlc3RzIHRoYXQgdGhlcmUgbWlnaHQgYmUgZ3JlYXRlciBoZXRlcm9nZW5laXR5IG9yIGRpdmVyc2l0eSB3aXRoaW4gdGhlIENEOCBjZWxsIHBvcHVsYXRpb24gaW4gdGVybXMgb2YgdGhlIGdlbmUgZXhwcmVzc2lvbiBwYXR0ZXJucyBjYXB0dXJlZCBieSBQQzEuIE9uIHRoZSBvdGhlciBoYW5kLCB0aGUgQ0Q0IGFuZCBOSyBwb3B1bGF0aW9ucyBzZWVtIHRvIGJlIG1vcmUgdGlnaHRseSBjbHVzdGVyZWQgb3IgaGF2ZSBsZXNzIHZhcmlhdGlvbiBhbG9uZyBQQzEuCgpgYGB7ciBQQzEgdnMgY2x1c3RlciBib3hwbG90cyBxdWVyeTIsIGVjaG89VH0KZ2dwbG90KHF1ZXJ5MiwgYWVzKHggPSBDZWxsVHlwZXMsIHkgPSBQQzEsIGZpbGwgPSBDZWxsVHlwZXMpKSArCiAgICBnZW9tX2JveHBsb3QoKSArCiAgICB0aGVtZV9idygpICsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpICsKICAgIGd1aWRlcyhmaWxsID0gIm5vbmUiKSArCiAgICB4bGFiKCJDZWxsVHlwZXMiKSArCiAgICB5bGFiKCJQQzEiKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gInJlZCIpCmBgYAoKIyMgQm94cGxvdHMgb2YgUEMyIHZzIENlbGwgdHlwZXMKClBDMiBjb250cmlidXRlcyB0byB0aGUgc2VwYXJhdGlvbiBvZiBOSyBjZWxscyBmcm9tIHRoZSBvdGhlciB0d28gY2VsbCB0eXBlcy4KCmBgYHtyIFBDMiB2cyBjbHVzdGVyIGJveHBsb3RzIHF1ZXJ5IDIsIGVjaG89VH0KZ2dwbG90KHF1ZXJ5MiwgYWVzKHggPSBDZWxsVHlwZXMsIHkgPSBQQzIsIGZpbGwgPSBDZWxsVHlwZXMpKSArCiAgICBnZW9tX2JveHBsb3QoKSArCiAgICB0aGVtZV9idygpICsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpICsKICAgIGd1aWRlcyhmaWxsID0gIm5vbmUiKSArCiAgICB4bGFiKCJDZWxsVHlwZXMiKSArCiAgICB5bGFiKCJQQzIiKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gInJlZCIpCmBgYAoKIyBRdWVyeSBkYXRhc2V0IHdoZW4gQ0Q4IGNlbGwgdHlwZSBpcyByZW1vdmVkIGZyb20gcmVmZXJlbmNlIGRhdGFzZXQKCkluIHRoaXMgc2VjdGlvbiwgd2UgZm9jdXMgb24gdGhlIHF1ZXJ5IGRhdGFzZXQgdGhhdCB3YXMgZ2VuZXJhdGVkIGFmdGVyIHJlbW92aW5nIENEOCBjZWxsIHR5cGVzIGZyb20gdGhlIHJlZmVyZW5jZSBkYXRhc2V0LiBXZSBwZXJmb3JtIGFuYWx5c2lzIG9uIHRoaXMgbW9kaWZpZWQgZGF0YXNldCB0byBleHBsb3JlIGhvdyB0aGUgUHJpbmNpcGFsIENvbXBvbmVudHMgKFBDcykgZGVyaXZlZCBmcm9tIFBDQSByZWxhdGUgdG8gdGhlIHByZWRpY3RlZCBjZWxsIGxhYmVscy4KCkZyb20gdGhlIHBsb3QsIHdlIGNhbiBzZWUgdGhhdCBQQzEgYW5kIFBDMiBjYXB0dXJlIHRoZSBtYWpvcml0eSBvZiB0aGUgdmFyaWFuY2UgaW4gdGhlIGRhdGEsIHdpdGggUEMxIGV4cGxhaW5pbmcgdGhlIG1vc3QgdmFyaWFuY2UuIFRoZSBzdWJzZXF1ZW50IFBDcyAoUEMzIHRvIFBDMTApIGNhcHR1cmUgbGVzcyB2YXJpYW5jZSBhbmQgbWF5IHJlcHJlc2VudCBzbWFsbGVyIG9yIG1vcmUgc3VidGxlIHBhdHRlcm5zIGluIHRoZSBkYXRhLgoKYGBge3IgUjIgcXVlcnkgKENEOCByZW12b3ZlZCBmcm9tIHJlZmVyZW5jZSksIGVjaG89VH0KCiMgRGF0YSBwcmVwYXJhdGlvbgpxdWVyeTMgPC0gZGF0YS5mcmFtZShyZWR1Y2VkRGltKHF1ZXJ5LCAiUENBIiksIENlbGxUeXBlcyA9IHRhYltbM11dJGFubm90YXRpb25zJGxhYmVscykKcnNxdWFyZWRfZGYgPC0gcmVncmVzc19QQ3MocXVlcnkzKQoKIyBDcmVhdGUgYSBsaW5lIHBsb3QgdXNpbmcgZ2dwbG90CmdncGxvdChyc3F1YXJlZF9kZiwgYWVzKHggPSBQQywgeSA9IFIyKSkgKwogIGdlb21fbGluZSgpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMTYpICsKICBsYWJzKHggPSAiUHJpbmNpcGFsIENvbXBvbmVudCAoUEMpIiwKICAgICAgIHkgPSAiUi1zcXVhcmVkIiwKICAgICAgIHRpdGxlID0gIlItc3F1YXJlZCBmb3IgUHJpbmNpcGFsIENvbXBvbmVudHMgKENEOCBjZWxscyByZW1vdmVkIGZyb20gcmVmZXJlbmNlIGRhdGFzZXQpIikgKwogIHlsaW0oMCwgMSkgKwogIHRoZW1lX2J3KCkgKyAKICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzID0gMToxMCwgbGFiZWxzID0gMToxMCkKYGBgCgojIFNjYXR0ZXIgcGxvdHMgYmV0d2VlbiBkaWZmZXJlbnQgUENzIGZvciBxdWVyeSBkYXRhc2V0IChmcm9tIHJlZmVyZW5jZSBDRDggY2VsbHMgcmVtb3ZlZCkKCldlIGNyZWF0ZWQgc2NhdHRlciBwbG90cyB0byB2aXN1YWxpemUgdGhlIFBDQSByZXN1bHRzIGZvciB0aGUgcXVlcnkgZGF0YXNldCB3aXRoIENEOCBjZWxsIHR5cGVzIHJlbW92ZWQgZnJvbSB0aGUgcmVmZXJlbmNlLgoKYGBge3IgU2FjdHRlciBwbG90cyBxdWVyeSAoQ0Q4IHJlbXZvdmVkIGZyb20gcmVmZXJlbmNlKSwgZWNobz1UfQojIERlZmluZSBjb2xvciBwYWxldHRlCnNlZWRzIDwtIGMoIiNGRjAwMDBGRiIsICIjQ0NGRjAwRkYiLCAiIzAwRkY2NkZGIiwgIiMwMDY2RkZGRiIsICIjQ0MwMEZGRkYiKQpjb2xvcl9wYWxldHRlIDwtIGNyZWF0ZVBhbGV0dGUobGVuZ3RoKHVuaXF1ZShxdWVyeTMkQ2VsbFR5cGUpKSwgc2VlZHMpCm5hbWVzKGNvbG9yX3BhbGV0dGUpIDwtIHVuaXF1ZShxdWVyeTMkQ2VsbFR5cGUpCmBgYAoKIyMgUEMxIHZzIFBDMiBzY2F0dGVyIHBsb3QKClRoZSBzY2F0dGVyIHBsb3Qgb2YgUEMxIGFnYWluc3QgUEMyIGZvciB0aGUgcXVlcnkgZGF0YXNldCwgd2l0aCByZWZlcmVuY2UgQ0Q4IGNlbGxzIHJlbW92ZWQsIHNob3dzIGNsZWFyIHNlcGFyYXRpb24gYmV0d2VlbiBkaWZmZXJlbnQgY2VsbCB0eXBlcy4gVGhpcyBzZXBhcmF0aW9uIGNvdWxkIGluZGljYXRlIHRoYXQgdGhlIHZhcmlhYmlsaXR5IGNhcHR1cmVkIGJ5IFBDMSBhbmQgUEMyIGlzIHNpZ25pZmljYW50IGVub3VnaCB0byBkaWZmZXJlbnRpYXRlIGJldHdlZW4gdGhlIHJlbWFpbmluZyBjZWxsIHR5cGVzIGluIHlvdXIgZGF0YXNldC4gCgpgYGB7ciBTYWN0dGVyIHBsb3RzIHF1ZXJ5IChDRDggcmVtdm92ZWQgZnJvbSByZWZlcmVuY2UpIFBDMSB2cyBQQzIsIGVjaG89VH0Kc2NhdHRlcl90b19wbG90bHkocXVlcnkzLCAiUEMxIiwgIlBDMiIsICJDZWxsVHlwZXMiLCAiUEMxIHZzIFBDMiIpCmBgYAoKIyMgUEMxIHZzIFBDMyBzY2F0dGVyIHBsb3QKCkNEMTQgY2VsbHMgYXJlIHNlcGFyYXRlZCBmcm9tIHRoZSBvdGhlciBjZWxsIHR5cGVzIGFsb25nIHRoZSBQQzMgYXhpcy4gVGhpcyBpbmRpY2F0ZXMgdGhhdCB0aGUgdmFyaWF0aW9uIGNhcHR1cmVkIGJ5IFBDMyBjb250cmlidXRlcyBzaWduaWZpY2FudGx5IHRvIHRoZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIENEMTQgY2VsbHMgYW5kIHRoZSByZXN0LiAKCmBgYHtyIFNhY3R0ZXIgcGxvdHMgcXVlcnkgKENEOCByZW12b3ZlZCBmcm9tIHJlZmVyZW5jZSkgUEMxIHZzIFBDMywgZWNobz1UfQpzY2F0dGVyX3RvX3Bsb3RseShxdWVyeTMsICJQQzMiLCAiUEMxIiwgIkNlbGxUeXBlcyIsICJQQzEgdnMgUEMzIikKYGBgCgojIyBQQzIgdnMgUEMzIHNjYXR0ZXIgcGxvdAoKYGBge3IgU2FjdHRlciBwbG90cyBxdWVyeSAoQ0Q4IHJlbXZvdmVkIGZyb20gcmVmZXJlbmNlKSBQQzIgdnMgUEMzLCBlY2hvPVR9CnNjYXR0ZXJfdG9fcGxvdGx5KHF1ZXJ5MywgIlBDMyIsICJQQzIiLCAiQ2VsbFR5cGVzIiwgIlBDMiB2cyBQQzMiKQpgYGAKCiMjIEJveHBsb3RzIG9mIFBDMSB2cyBDZWxsIHR5cGVzCgpgYGB7ciBQQzEgdnMgY2x1c3RlciBib3hwbG90cyBxdWVyeTMsIGVjaG8gPVR9CmdncGxvdChxdWVyeTMsIGFlcyh4ID0gQ2VsbFR5cGVzLCB5ID0gUEMxLCBmaWxsID0gQ2VsbFR5cGVzKSkgKwogICAgZ2VvbV9ib3hwbG90KCkgKwogICAgdGhlbWVfYncoKSArCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSArCiAgICBndWlkZXMoZmlsbCA9ICJub25lIikgKwogICAgeGxhYigiQ2VsbFR5cGVzIikgKwogICAgeWxhYigiUEMxIikgKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJyZWQiKQpgYGAKCiMjIEJveHBsb3RzIG9mIFBDMiB2cyBDZWxsIHR5cGVzCgpgYGB7ciBQQzIgdnMgY2x1c3RlciBib3hwbG90cyBxdWVyeTMsIGVjaG89VH0KZ2dwbG90KHF1ZXJ5MywgYWVzKHggPSBDZWxsVHlwZXMsIHkgPSBQQzIsIGZpbGwgPSBDZWxsVHlwZXMpKSArCiAgICBnZW9tX2JveHBsb3QoKSArCiAgICB0aGVtZV9idygpICsKICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTAsIGhqdXN0ID0gMSkpICsKICAgIGd1aWRlcyhmaWxsID0gIm5vbmUiKSArCiAgICB4bGFiKCJDZWxsVHlwZXMiKSArCiAgICB5bGFiKCJQQzIiKSArIGdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIGxpbmV0eXBlID0gImRhc2hlZCIsIGNvbG9yID0gInJlZCIpCmBgYAoKIyMgQm94cGxvdHMgb2YgUEMzIHZzIENlbGwgdHlwZXMKCmBgYHtyIFBDMyB2cyBjbHVzdGVyIGJveHBsb3RzIHF1ZXJ5MywgZWNobz1UfQpnZ3Bsb3QocXVlcnkzLCBhZXMoeCA9IENlbGxUeXBlcywgeSA9IFBDMywgZmlsbCA9IENlbGxUeXBlcykpICsKICAgIGdlb21fYm94cGxvdCgpICsKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkgKwogICAgZ3VpZGVzKGZpbGwgPSAibm9uZSIpICsKICAgIHhsYWIoIkNlbGxUeXBlcyIpICsKICAgIHlsYWIoIlBDMyIpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAicmVkIikKYGBgCgojIFF1ZXJ5IGRhdGFzZXQgd2hlbiBOSyBjZWxsIHR5cGUgaXMgcmVtb3ZlZCBmcm9tIHJlZmVyZW5jZSBkYXRhc2V0CgpJbiB0aGlzIHNlY3Rpb24sIHdlIGZvY3VzIG9uIHRoZSBxdWVyeSBkYXRhc2V0IHRoYXQgd2FzIGdlbmVyYXRlZCBhZnRlciByZW1vdmluZyBOSyBjZWxsIHR5cGVzIGZyb20gdGhlIHJlZmVyZW5jZSBkYXRhc2V0LiBXZSBwZXJmb3JtIGFuYWx5c2lzIG9uIHRoaXMgbW9kaWZpZWQgZGF0YXNldCB0byBleHBsb3JlIGhvdyB0aGUgUHJpbmNpcGFsIENvbXBvbmVudHMgKFBDcykgZGVyaXZlZCBmcm9tIFBDQSByZWxhdGUgdG8gdGhlIHByZWRpY3RlZCBjZWxsIGxhYmVscy4KClBDMSBoYXMgYW4gUi1zcXVhcmVkIHZhbHVlIG9mIDAuOTQ5LCBpbmRpY2F0aW5nIHRoYXQgaXQgY2FwdHVyZXMgYSBzdWJzdGFudGlhbCBhbW91bnQgb2YgdmFyaWF0aW9uIGluIHRoZSBkYXRhc2V0LiBJdCBzdWdnZXN0cyB0aGF0IFBDMSBleHBsYWlucyBhIGxhcmdlIHBvcnRpb24gb2YgdGhlIHRvdGFsIHZhcmlhYmlsaXR5LgoKUEMyIGhhcyBhbiBSLXNxdWFyZWQgdmFsdWUgb2YgMC4xODUsIHdoaWNoIGlzIHNpZ25pZmljYW50bHkgbG93ZXIgdGhhbiBQQzEuIFRoaXMgbWVhbnMgdGhhdCBQQzIgZXhwbGFpbnMgYSBzbWFsbGVyIHBvcnRpb24gb2YgdGhlIHRvdGFsIHZhcmlhYmlsaXR5IGNvbXBhcmVkIHRvIFBDMS4KClBDMyBoYXMgYW4gUi1zcXVhcmVkIHZhbHVlIG9mIDAuMzk2LCBpbmRpY2F0aW5nIHRoYXQgaXQgY2FwdHVyZXMgYSBtb2RlcmF0ZSBhbW91bnQgb2YgdmFyaWF0aW9uLiBJdCdzIGhpZ2hlciB0aGFuIFBDMiBidXQgbm90IGFzIGhpZ2ggYXMgUEMxLgoKUENzIDQgdG8gMTAgaGF2ZSBtdWNoIGxvd2VyIFItc3F1YXJlZCB2YWx1ZXMgcmFuZ2luZyBmcm9tIDAuMDI0IHRvIDAuMDAxLCBzdWdnZXN0aW5nIHRoYXQgdGhleSBleHBsYWluIHJlbGF0aXZlbHkgc21hbGwgYW1vdW50cyBvZiB2YXJpYXRpb24gaW4gdGhlIGRhdGFzZXQuCgpgYGB7ciBSMiBxdWVyeSAoTksgcmVtdm92ZWQgZnJvbSByZWZlcmVuY2UpLCBlY2hvPVR9CiMgRGF0YSBwcmVwYXJhdGlvbgpxdWVyeTQgPC0gZGF0YS5mcmFtZShyZWR1Y2VkRGltKHF1ZXJ5LCAiUENBIiksIENlbGxUeXBlcyA9IHRhYltbNF1dJGFubm90YXRpb25zJGxhYmVscykKcnNxdWFyZWRfZGYgPC0gcmVncmVzc19QQ3MocXVlcnk0KQoKIyBDcmVhdGUgYSBsaW5lIHBsb3QgdXNpbmcgZ2dwbG90CmdncGxvdChyc3F1YXJlZF9kZiwgYWVzKHggPSBQQywgeSA9IFIyKSkgKwogIGdlb21fbGluZSgpICsKICBnZW9tX3BvaW50KHNoYXBlID0gMTYpICsKICBsYWJzKHggPSAiUHJpbmNpcGFsIENvbXBvbmVudCAoUEMpIiwKICAgICAgIHkgPSAiUi1zcXVhcmVkIiwKICAgICAgIHRpdGxlID0gIlItc3F1YXJlZCBmb3IgUHJpbmNpcGFsIENvbXBvbmVudHMgKE5LIGNlbGxzIHJlbW92ZWQgZnJvbSByZWZlcmVuY2UgZGF0YXNldCkiKSArCiAgeWxpbSgwLCAxKSArCiAgdGhlbWVfYncoKSArIAogIHNjYWxlX3hfY29udGludW91cyhicmVha3MgPSAxOjEwLCBsYWJlbHMgPSAxOjEwKQpgYGAKCiMgU2NhdHRlciBwbG90cyBiZXR3ZWVuIGRpZmZlcmVudCBQQ3MgZm9yIHF1ZXJ5IGRhdGFzZXQgKGZyb20gcmVmZXJlbmNlIE5LIGNlbGxzIHJlbW92ZWQpCgpXZSBjcmVhdGUgc2NhdHRlciBwbG90cyB0byB2aXN1YWxpemUgdGhlIFBDQSByZXN1bHRzIGZvciB0aGUgcXVlcnkgZGF0YXNldCB3aXRoIE5LIGNlbGwgdHlwZXMgcmVtb3ZlZCBmcm9tIHRoZSByZWZlcmVuY2UuCgpgYGB7ciBTYWN0dGVyIHBsb3RzIHF1ZXJ5IChOSyByZW12b3ZlZCBmcm9tIHJlZmVyZW5jZSksIGVjaG89VH0KCiMgRGVmaW5lIGNvbG9yIHBhbGV0dGUKc2VlZHMgPC0gYygiI0ZGMDAwMEZGIiwgIiNDQ0ZGMDBGRiIsICIjMDBGRjY2RkYiLCAiIzAwNjZGRkZGIiwgIiNDQzAwRkZGRiIpCmNvbG9yX3BhbGV0dGUgPC0gY3JlYXRlUGFsZXR0ZShsZW5ndGgodW5pcXVlKHF1ZXJ5NCRDZWxsVHlwZSkpLCBzZWVkcykKbmFtZXMoY29sb3JfcGFsZXR0ZSkgPC0gdW5pcXVlKHF1ZXJ5NCRDZWxsVHlwZSkKYGBgCgojIyBQQzEgdnMgUEMyIHNjYXR0ZXIgcGxvdAoKQ0QxNCBjZWxscyBhcmUgd2VsbCBzZXBhcmF0ZWQgZnJvbSB0aGUgb3RoZXIgY2VsbCB0eXBlcyBhbG9uZyB0aGUgUEMxIGF4aXMuCgpUaGVyZSBhcmUgdHdvIGRpc3RpbmN0IHBvcHVsYXRpb25zIG9mIENEOCBjZWxsczogb25lIHBvcHVsYXRpb24gaXMgc29tZXdoYXQgc2VwYXJhdGUgZnJvbSB0aGUgb3RoZXIsIGFuZCB0aGUgbGF0dGVyIHBvcHVsYXRpb24gaGFzIHNvbWUgb3ZlcmxhcCB3aXRoIENENCBjZWxscy4KCmBgYHtyIFNhY3R0ZXIgcGxvdHMgcXVlcnkgKE5LIHJlbXZvdmVkIGZyb20gcmVmZXJlbmNlKSBQQzEgdnMgUEMyLCBlY2hvPVR9CnNjYXR0ZXJfdG9fcGxvdGx5KHF1ZXJ5NCwgIlBDMSIsICJQQzIiLCAiQ2VsbFR5cGVzIiwgIlBDMSB2cyBQQzIiKQpgYGAKCiMjIFBDMSB2cyBQQzMgc2NhdHRlciBwbG90CgpDRDE0IGNlbGxzIGNvbnRpbnVlIHRvIHNob3cgYSBjbGVhciBzZXBhcmF0aW9uIGZyb20gdGhlIG90aGVyIGNlbGwgdHlwZXMsIGluZGljYXRpbmcgZGlzdGluY3QgZGlmZmVyZW5jZXMgaW4gZ2VuZSBleHByZXNzaW9uIHBhdHRlcm5zIG9yIG90aGVyIG1vbGVjdWxhciBjaGFyYWN0ZXJpc3RpY3MuCgpgYGB7ciBTYWN0dGVyIHBsb3RzIHF1ZXJ5IChOSyByZW12b3ZlZCBmcm9tIHJlZmVyZW5jZSkgUEMxIHZzIFBDMywgZWNobz1UfQpzY2F0dGVyX3RvX3Bsb3RseShxdWVyeTQsICJQQzMiLCAiUEMxIiwgIkNlbGxUeXBlcyIsICJQQzEgdnMgUEMzIikKYGBgCgojIyBQQzEgdnMgUEM0IHNjYXR0ZXIgcGxvdAoKYGBge3IgU2FjdHRlciBwbG90cyBxdWVyeSAoTksgcmVtdm92ZWQgZnJvbSByZWZlcmVuY2UpIFBDMSB2cyBQQzQsIGVjaG89VH0Kc2NhdHRlcl90b19wbG90bHkocXVlcnk0LCAiUEM0IiwgIlBDMSIsICJDZWxsVHlwZXMiLCAiUEMxIHZzIFBDNCIpCmBgYAoKIyMgUEMyIHZzIFBDMyBzY2F0dGVyIHBsb3QKCmBgYHtyIFNhY3R0ZXIgcGxvdHMgcXVlcnkgKE5LIHJlbXZvdmVkIGZyb20gcmVmZXJlbmNlKSBQQzIgdnMgUEMzLCBlY2hvPVR9CnNjYXR0ZXJfdG9fcGxvdGx5KHF1ZXJ5NCwgIlBDMyIsICJQQzIiLCAiQ2VsbFR5cGVzIiwgIlBDMyB2cyBQQzIiKQpgYGAKCiMjIFBDMyB2cyBQQzQgc2NhdHRlciBwbG90CgpgYGB7ciBTYWN0dGVyIHBsb3RzIHF1ZXJ5IChOSyByZW12b3ZlZCBmcm9tIHJlZmVyZW5jZSkgUEMzIHZzIFBDNCwgZWNobz1UfQpzY2F0dGVyX3RvX3Bsb3RseShxdWVyeTQsICJQQzMiLCAiUEM0IiwgIkNlbGxUeXBlcyIsICJQQzMgdnMgUEM0IikKYGBgCgojIyBCb3hwbG90cyBvZiBQQzEgdnMgQ2VsbCB0eXBlcwoKUEMxIGNhcHR1cmVzIHNpZ25pZmljYW50IHZhcmlhdGlvbiB0aGF0IGRpc3Rpbmd1aXNoZXMgQ0QxNCBjZWxscyBmcm9tIENENCBhbmQgQ0Q4IGNlbGxzLgoKYGBge3IgUEMxIHZzIGNsdXN0ZXIgYm94cGxvdHMgcXVlcnk0LCBlY2hvPVR9CmdncGxvdChxdWVyeTQsIGFlcyh4ID0gQ2VsbFR5cGVzLCB5ID0gUEMxLCBmaWxsID0gQ2VsbFR5cGVzKSkgKwogICAgZ2VvbV9ib3hwbG90KCkgKwogICAgdGhlbWVfYncoKSArCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSArCiAgICBndWlkZXMoZmlsbCA9ICJub25lIikgKwogICAgeGxhYigiQ2VsbFR5cGVzIikgKwogICAgeWxhYigiUEMxIikgKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJyZWQiKQpgYGAKCiMjIEJveHBsb3RzIG9mIFBDMiB2cyBDZWxsIHR5cGVzCgpUaGUgZm9sbG93aW5nIGFuYWx5c2lzIHJldmVhbHM6CgpDRDggQ2VsbCBQb3B1bGF0aW9uIFNwcmVhZDogVGhlIG5vdGljZWFibGUgc3ByZWFkIGluIHRoZSBDRDggY2VsbCBwb3B1bGF0aW9uIGFsb25nIFBDMiBpbmRpY2F0ZXMgdGhhdCB0aGVyZSBpcyBzaWduaWZpY2FudCB2YXJpYWJpbGl0eSBpbiB0aGUgZ2VuZSBleHByZXNzaW9uIG9yIG1vbGVjdWxhciBjaGFyYWN0ZXJpc3RpY3Mgb2YgQ0Q4IGNlbGxzIHRoYXQgaXMgY2FwdHVyZWQgYnkgdGhpcyBwcmluY2lwYWwgY29tcG9uZW50LiBUaGlzIHNwcmVhZCBtaWdodCBzdWdnZXN0IHRoYXQgdGhlcmUgYXJlIHN1Ymdyb3VwcyBvciBzdWJ0eXBlcyB3aXRoaW4gdGhlIENEOCBjZWxsIHBvcHVsYXRpb24gdGhhdCBleGhpYml0IGRpc3RpbmN0IHBhdHRlcm5zIGFsb25nIFBDMi4KClR3byBDRDggQ2VsbCBQb3B1bGF0aW9uczogVGhlIHByZXNlbmNlIG9mIHR3byBkaXN0aW5jdCBDRDggY2VsbCBwb3B1bGF0aW9ucyBpbiB0aGUgUEMxIHZzIFBDMiBzY2F0dGVyIHBsb3QgYWxpZ25zIHdpdGggdGhlIHNwcmVhZCBzZWVuIGluIHRoZSBib3hwbG90cyBvZiBQQzIgdnMgQ2VsbCB0eXBlcy4gVGhpcyBzdWdnZXN0cyB0aGF0IHRoZSB2YXJpYXRpb24gY2FwdHVyZWQgYnkgUEMyIGNvbnRyaWJ1dGVzIHRvIHRoZSBkaWZmZXJlbnRpYXRpb24gYmV0d2VlbiB0aGVzZSB0d28gQ0Q4IGNlbGwgcG9wdWxhdGlvbnMuIFRoZSBzcHJlYWQgc2VlbiBpbiB0aGUgYm94cGxvdHMgbWlnaHQgYmUgYXR0cmlidXRlZCB0byB0aGUgZGlmZmVyZW5jZXMgYmV0d2VlbiB0aGVzZSBwb3B1bGF0aW9ucyBpbiB0ZXJtcyBvZiB0aGUgY2FwdHVyZWQgdmFyaWF0aW9uIGFsb25nIFBDMi4KCmBgYHtyIFBDMiB2cyBjbHVzdGVyIGJveHBsb3RzIHF1ZXJ5NCwgZWNobz1UfQpnZ3Bsb3QocXVlcnk0LCBhZXMoeCA9IENlbGxUeXBlcywgeSA9IFBDMiwgZmlsbCA9IENlbGxUeXBlcykpICsKICAgIGdlb21fYm94cGxvdCgpICsKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgaGp1c3QgPSAxKSkgKwogICAgZ3VpZGVzKGZpbGwgPSAibm9uZSIpICsKICAgIHhsYWIoIkNlbGxUeXBlcyIpICsKICAgIHlsYWIoIlBDMiIpICsgZ2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgbGluZXR5cGUgPSAiZGFzaGVkIiwgY29sb3IgPSAicmVkIikKYGBgCgojIyBCb3hwbG90cyBvZiBQQzMgdnMgQ2VsbCB0eXBlcwoKYGBge3IgUEMzIHZzIGNsdXN0ZXIgYm94cGxvdHMgcXVlcnk0LCBlY2hvPVR9CmdncGxvdChxdWVyeTQsIGFlcyh4ID0gQ2VsbFR5cGVzLCB5ID0gUEMzLCBmaWxsID0gQ2VsbFR5cGVzKSkgKwogICAgZ2VvbV9ib3hwbG90KCkgKwogICAgdGhlbWVfYncoKSArCiAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCBoanVzdCA9IDEpKSArCiAgICBndWlkZXMoZmlsbCA9ICJub25lIikgKwogICAgeGxhYigiQ2VsbFR5cGVzIikgKwogICAgeWxhYigiUEMzIikgKyBnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBsaW5ldHlwZSA9ICJkYXNoZWQiLCBjb2xvciA9ICJyZWQiKQpgYGAKCiMgRGlzdGFuY2UgYW5hbHlzaXMgYmV0d2VlbiBkaXN0aW5jdCBjZWxsIHR5cGVzIG9mIHJlZmVyZW5jZSBhbmQgcXVlcnkgZGF0YXNldAoKTm90ZTogRGlzdGFuY2VzIGFyZSBiZWluZyBjYWxjdWxhdGVkIGZvciBjZWxsIHR5cGVzIGluIG9yaWdpbmFsL29ic2VydmVkIHJlZmVyZW5jZSBhbmQgcXVlcnkgZGF0YXNldC4KCklkZW50aWZpZWQgbWFya2VyIGdlbmVzIHVzaW5nIHRyYWluU2luZ2xlUigpIGZ1bmN0aW9uIGZyb20gU2luZ2xlUiBwYWNrYWdlIGFuZCB1c2VkIHRoZXNlIGdlbmVzIHRvIGNvbXB1dGUgCmRpc3RhbmNlcyBiZXR3ZWVuIGNlbGxzIGluIHJlZmVyZW5jZSBhbmQgcXVlcnkgZGF0YXNldC4KCmBgYHtyIFNpbmdsZVIgZ2VuZXMsIGVjaG89Riwgd2FybmluZz1GfQojIyBUcmFpbiBTaW5nbGVSIGNsYXNzaWZpZXIgdG8gZ2V0IGxpc3Qgb2YgZ2VuZXMKdHJhaW4gPC0gdHJhaW5TaW5nbGVSKAogIHJlZmVyZW5jZSwKICByZWZlcmVuY2UkbGFiZWwpCgptYXJrZXJzIDwtIHRyYWluJG1hcmtlcnMkdW5pcXVlCgojIEV4dHJhY3QgbGFiZWxzIGZyb20gZWFjaCBlbGVtZW50IGluIHRoZSAndGFiJyBsaXN0IHVzaW5nIGxhcHBseQpsYWJlbF9saXN0cyA8LSBsYXBwbHkodGFiLCBmdW5jdGlvbih4KSB4JGFubm90YXRpb25zJGxhYmVscykKYW5ub3RhdGlvbnMgPC0gZG8uY2FsbChkYXRhLmZyYW1lLCBsYWJlbF9saXN0cykKY29sbmFtZXMoYW5ub3RhdGlvbnMpIDwtIGMoImxhYmVsc19DRDRfcmVtb3ZlZCIsICJsYWJlbHNfQ0QxNF9yZW1vdmVkIiwgImxhYmVsc19DRDhfcmVtb3ZlZCIsICJsYWJlbHNfTktfcmVtb3ZlZCIpCgojIEFkZCBhbm5vdGF0aW9ucyB0byBxdWVyeSBkYXRhc2V0CmNvbERhdGEocXVlcnkpWyxjKCJsYWJlbHNfQ0Q0X3JlbW92ZWQiLCAibGFiZWxzX0NEMTRfcmVtb3ZlZCIsICJsYWJlbHNfQ0Q4X3JlbW92ZWQiLCAibGFiZWxzX05LX3JlbW92ZWQiKV0gPC0gYW5ub3RhdGlvbnMKCiMgU3Vic2V0IHF1ZXJ5IGFuZCByZWZlcmVuY2UgZGF0YXNldCBiYXNlZCBvbiBtYXJrZXJzCnF1ZXJ5X3N1YnNldCA8LSBxdWVyeVttYXJrZXJzLCBdCnJlZmVyZW5jZV9zdWJzZXQgPC0gcmVmZXJlbmNlW21hcmtlcnMsIF0KYGBgCgojIyBEaXN0YW5jZSBiZXR3ZWVuIENENCBjZWxscyBpbiByZWZlcmVuY2UgYW5kIHF1ZXJ5CgpgYGB7ciBDRDQgZ2VuZXMsIGVjaG89VH0KY2FsY3VsYXRlUGFpcndpc2VEaXN0YW5jZXNBbmRQbG90RGVuc2l0eShxdWVyeV9zdWJzZXQsIHJlZmVyZW5jZV9zdWJzZXQsICJsYWJlbCIsICJsYWJlbCIsICJDRDQiLCAiQ0Q0IiwgImV1Y2xpZGVhbiIpCmBgYAoKIyMgRGlzdGFuY2UgYmV0d2VlbiBDRDE0IGNlbGxzIGluIHJlZmVyZW5jZSBhbmQgcXVlcnkKCmBgYHtyIENEMTQgZ2VuZXMsIGVjaG89VH0KY2FsY3VsYXRlUGFpcndpc2VEaXN0YW5jZXNBbmRQbG90RGVuc2l0eShxdWVyeV9zdWJzZXQsIHJlZmVyZW5jZV9zdWJzZXQsICJsYWJlbCIsICJsYWJlbCIsICJDRDE0IiwgIkNEMTQiLCAiZXVjbGlkZWFuIikKYGBgCgojIyBEaXN0YW5jZSBiZXR3ZWVuIENEOCBjZWxscyBpbiByZWZlcmVuY2UgYW5kIHF1ZXJ5CgpgYGB7ciBDRDggZ2VuZXMsIGVjaG89VH0KY2FsY3VsYXRlUGFpcndpc2VEaXN0YW5jZXNBbmRQbG90RGVuc2l0eShxdWVyeV9zdWJzZXQsIHJlZmVyZW5jZV9zdWJzZXQsICJsYWJlbCIsICJsYWJlbCIsICJDRDgiLCAiQ0Q4IiwgImV1Y2xpZGVhbiIpCmBgYAoKIyMgRGlzdGFuY2UgYmV0d2VlbiBOSyBjZWxscyBpbiByZWZlcmVuY2UgYW5kIHF1ZXJ5CgpgYGB7ciBOSyBnZW5lcywgZWNobz1UfQpjYWxjdWxhdGVQYWlyd2lzZURpc3RhbmNlc0FuZFBsb3REZW5zaXR5KHF1ZXJ5X3N1YnNldCwgcmVmZXJlbmNlX3N1YnNldCwgImxhYmVsIiwgImxhYmVsIiwgIk5LIiwgIk5LIiwgImV1Y2xpZGVhbiIpCmBgYAoKIyBEaXN0YW5jZSBhbmFseXNpcyBiZXR3ZWVuIGNlbGwgdHlwZXMgcmVtb3ZlZCBmcm9tIHJlZmVyZW5jZSBhbmQgYXNzaWduZWQgY2VsbCB0eXBlIGluIHF1ZXJ5IGRhdGFzZXQKCkluIHRoaXMgc2VjdGlvbiwgd2UgY2FsY3VsYXRlIEV1Y2xpZGVhbiBkaXN0YW5jZXMgYmV0d2VlbiB0aGUgcmVtb3ZlZCBjZWxsIHR5cGVzIGluIHRoZSByZWZlcmVuY2UgYW5kIHRoZWlyIGFzc2lnbmVkIGNlbGwgdHlwZXMgaW4gdGhlIHF1ZXJ5LgoKYGBge3IgZGF0YSBwcm9jZXNzaW5nIGZvciBkaXN0YW5jZSBhbmFsc3lpcywgZWNobz1UfQojIEV4dHJhY3QgbGFiZWxzIGZyb20gZWFjaCBlbGVtZW50IGluIHRoZSAndGFiJyBsaXN0IHVzaW5nIGxhcHBseQpsYWJlbF9saXN0cyA8LSBsYXBwbHkodGFiLCBmdW5jdGlvbih4KSB4JGFubm90YXRpb25zJGxhYmVscykKYW5ub3RhdGlvbnMgPC0gZG8uY2FsbChkYXRhLmZyYW1lLCBsYWJlbF9saXN0cykKY29sbmFtZXMoYW5ub3RhdGlvbnMpIDwtIGMoImxhYmVsc19DRDRfcmVtb3ZlZCIsICJsYWJlbHNfQ0QxNF9yZW1vdmVkIiwgImxhYmVsc19DRDhfcmVtb3ZlZCIsICJsYWJlbHNfTktfcmVtb3ZlZCIpCmBgYAoKIyMgRGlzdGFuY2UgY29tcHV0YXRpb24gYmV0d2VlbiBDRDQgY2VsbHMgaW4gcXVlcnkgYW5kIENEOCBjZWxscyBpbiByZWZlcmVuY2UKCldoZW4sIENEOCBjZWxscyB3ZXJlIHJlbW92ZWQgZnJvbSB0aGUgcmVmZXJlbmNlIGFuZCB3aGVuIHRoaXMgcmVmZXJlbmNlIHdhcyB1c2VkIHRvIGFubm90YXRlIHRoZSBxdWVyeSBkYXRhc2V0LCB0aGVzZSBjZWxscyB3ZXJlIGFzc2lnbmVkIGFzIENENCBpbiBxdWVyeS4KCmBgYHtyIENEOCB2cyBDRDQgZ2VuZXMsIGVjaG89VH0KY2FsY3VsYXRlUGFpcndpc2VEaXN0YW5jZXNBbmRQbG90RGVuc2l0eShxdWVyeV9zdWJzZXQsIHJlZmVyZW5jZV9zdWJzZXQsICJsYWJlbHNfQ0Q0X3JlbW92ZWQiLCAibGFiZWwiLCAiQ0Q4IiwgIkNENCIsICJldWNsaWRlYW4iKQpgYGAKCiMjIERpc3RhbmNlIGNvbXB1dGF0aW9uIGJldHdlZW4gQ0Q4IGNlbGxzIGluIHF1ZXJ5IGFuZCBDRDE0IGNlbGxzIGluIHJlZmVyZW5jZQoKV2hlbiwgQ0QxNCBjZWxscyB3ZXJlIHJlbW92ZWQgZnJvbSB0aGUgcmVmZXJlbmNlIGFuZCB3aGVuIHRoaXMgcmVmZXJlbmNlIHdhcyB1c2VkIHRvIGFubm90YXRlIHRoZSBxdWVyeSBkYXRhc2V0LCB0aGVzZSBjZWxscyB3ZXJlIGFzc2lnbmVkIGFzIENEOCBpbiBxdWVyeS4KCmBgYHtyIENEMTQgdnMgQ0Q0IGdlbmVzLCBlY2hvPVR9CmNhbGN1bGF0ZVBhaXJ3aXNlRGlzdGFuY2VzQW5kUGxvdERlbnNpdHkocXVlcnlfc3Vic2V0LCByZWZlcmVuY2Vfc3Vic2V0LCAibGFiZWxzX0NEMTRfcmVtb3ZlZCIsICJsYWJlbCIsICJDRDgiLCAiQ0QxNCIsICJldWNsaWRlYW4iKQpgYGAKCiMjIERpc3RhbmNlIGNvbXB1dGF0aW9uIGJldHdlZW4gQ0Q0IGNlbGxzIGluIHF1ZXJ5IGFuZCBDRDggY2VsbHMgaW4gcmVmZXJlbmNlCgpXaGVuLCBDRDggY2VsbHMgd2VyZSByZW1vdmVkIGZyb20gdGhlIHJlZmVyZW5jZSBhbmQgd2hlbiB0aGlzIHJlZmVyZW5jZSB3YXMgdXNlZCB0byBhbm5vdGF0ZSB0aGUgcXVlcnkgZGF0YXNldCwgdGhlc2UgY2VsbHMgd2VyZSBhc3NpZ25lZCBhcyBDRDQgaW4gcXVlcnkuCgpgYGB7ciBDRDQgdnMgQ0Q4IGdlbmVzLCBlY2hvPVR9CmNhbGN1bGF0ZVBhaXJ3aXNlRGlzdGFuY2VzQW5kUGxvdERlbnNpdHkocXVlcnlfc3Vic2V0LCByZWZlcmVuY2Vfc3Vic2V0LCAibGFiZWxzX0NEOF9yZW1vdmVkIiwgImxhYmVsIiwgIkNENCIsICJDRDgiLCAiZXVjbGlkZWFuIikKYGBgCgojIyBEaXN0YW5jZSBjb21wdXRhdGlvbiBiZXR3ZWVuIENEOCBjZWxscyBpbiBxdWVyeSBhbmQgTksgY2VsbHMgaW4gcmVmZXJlbmNlCgpXaGVuLCBOSyBjZWxscyB3ZXJlIHJlbW92ZWQgZnJvbSB0aGUgcmVmZXJlbmNlIGFuZCB3aGVuIHRoaXMgcmVmZXJlbmNlIHdhcyB1c2VkIHRvIGFubm90YXRlIHRoZSBxdWVyeSBkYXRhc2V0LCB0aGVzZSBjZWxscyB3ZXJlIGFzc2lnbmVkIGFzIENEOCBpbiBxdWVyeS4KCmBgYHtyIENEOCB2cyBOSyBnZW5lcywgZWNobz1UfQpjYWxjdWxhdGVQYWlyd2lzZURpc3RhbmNlc0FuZFBsb3REZW5zaXR5KHF1ZXJ5X3N1YnNldCwgcmVmZXJlbmNlX3N1YnNldCwgImxhYmVsc19OS19yZW1vdmVkIiwgImxhYmVsIiwgIkNEOCIsICJOSyIsICJldWNsaWRlYW4iKQpgYGAKCiMgUHJpbmNpcGFsIENvbXBvbmVudCBBbmFseXNpcyAoUENBKSBLZXkgT2JzZXJ2YXRpb25zOgoKQ0Q0IGFuZCBDRDggT3ZlcmxhcCBpbiBQQzEgdnMgUEMyIGluIHRoZSBRdWVyeToKVGhlIG92ZXJsYXAgb2JzZXJ2ZWQgYmV0d2VlbiBDRDQgYW5kIENEOCBjZWxscyBpbiB0aGUgUEMxIHZzIFBDMiBwbG90IG9mIHRoZSBxdWVyeSBkYXRhc2V0IHN1Z2dlc3RzIHRoZSBwcmVzZW5jZSBvZiBzaGFyZWQgZ2VuZSBleHByZXNzaW9uIHBhdHRlcm5zIGJldHdlZW4gdGhlc2UgdHdvIGNlbGwgdHlwZXMuIFRoaXMgc2hhcmVkIHBhdHRlcm4gbWlnaHQgbGVhZCB0byB0aGVpciBwcm94aW1pdHkgaW4gdGhlIFBDQSBzcGFjZS4KCkNEMTQsIENEOCwgYW5kIE5LIFNlcGFyYXRpb24gaW4gUEMxIHZzIFBDMiBBZnRlciBDRDQgUmVtb3ZhbDoKVXBvbiByZW1vdmluZyBDRDQgY2VsbHMgZnJvbSB0aGUgcmVmZXJlbmNlIGRhdGFzZXQsIHRoZXJlIGlzIGFuIGltcHJvdmVkIHNlcGFyYXRpb24gb2YgQ0QxNCwgQ0Q4LCBhbmQgTksgY2VsbHMgaW4gdGhlIFBDMSB2cyBQQzIgcGxvdC4gVGhpcyBlbmhhbmNlbWVudCBpbiBzZXBhcmF0aW9uIGNvdWxkIGJlIGF0dHJpYnV0ZWQgdG8gdGhlIHJlZHVjdGlvbiBvZiBub2lzZSBjYXVzZWQgYnkgQ0Q0IGNlbGxzLCBlbmFibGluZyBhIGNsZWFyZXIgZGlzdGluY3Rpb24gYmV0d2VlbiB0aGVzZSBjZWxsIHBvcHVsYXRpb25zLgoKVHdvIENEOCBQb3B1bGF0aW9ucyBpbiBQQzIgdnMgUEMzIEFmdGVyIENENCBSZW1vdmFsOgpUaGUgYWJzZW5jZSBvZiBDRDQgY2VsbHMgZnJvbSB0aGUgcmVmZXJlbmNlIGRhdGFzZXQgaGFzIHVuY292ZXJlZCBwcmV2aW91c2x5IG1hc2tlZCBoZXRlcm9nZW5laXR5IHdpdGhpbiBDRDggY2VsbHMuIFRoaXMgaXMgZXZpZGVudCBmcm9tIHRoZSBlbWVyZ2VuY2Ugb2YgdHdvIGRpc3RpbmN0IENEOCBzdWJwb3B1bGF0aW9ucyBpbiB0aGUgUEMyIHZzIFBDMyBwbG90LCBpbmRpY2F0aW5nIHRoYXQgQ0Q0IGNlbGxzIHdlcmUgaW5mbHVlbmNpbmcgdGhlIGdyb3VwaW5nIG9mIENEOCBjZWxscy4KClR3byBDRDggUG9wdWxhdGlvbnMgaW4gUEMxIHZzIFBDMiBBZnRlciBDRDE0IFJlbW92YWw6CkZvbGxvd2luZyB0aGUgcmVtb3ZhbCBvZiBDRDE0LCB0aGVyZSBhcmUgbm90YWJsZSBjaGFuZ2VzIGluIHRoZSB2YXJpYW5jZSBjYXB0dXJlZCBieSBQQzEgYW5kIFBDMi4gVGhpcyB1bm1hc2tpbmcgb2YgdmFyaWFiaWxpdHkgaGFzIGxlZCB0byB0aGUgaWRlbnRpZmljYXRpb24gb2YgdHdvIGRpc3RpbmN0IENEOCBzdWJwb3B1bGF0aW9ucyBpbiB0aGUgUEMxIHZzIFBDMiBwbG90LCBzdWdnZXN0aW5nIHRoYXQgQ0QxNCBjZWxscyB3ZXJlIG1hc2tpbmcgdGhpcyBoZXRlcm9nZW5laXR5LgoKVHdvIENENCBQb3B1bGF0aW9ucyBpbiBQQzIgdnMgUEMzIEFmdGVyIENEOCBSZW1vdmFsOgpUaGUgYWJzZW5jZSBvZiBDRDggVCBjZWxscyBpbiB0aGUgcmVmZXJlbmNlIGRhdGFzZXQgaGFzIHJldmVhbGVkIGhpZGRlbiB2YXJpYWJpbGl0eSB3aXRoaW4gQ0Q0IFQgY2VsbHMuIFRoaXMgaXMgZXZpZGVudCBmcm9tIHRoZSBhcHBlYXJhbmNlIG9mIHR3byBkaXN0aW5jdCBDRDQgc3VicG9wdWxhdGlvbnMgaW4gdGhlIFBDMiB2cyBQQzMgcGxvdCwgaGlnaGxpZ2h0aW5nIHRoYXQgdGhlIHByZXNlbmNlIG9mIENEOCBjZWxscyB3YXMgaW1wYWN0aW5nIHRoZSByZXByZXNlbnRhdGlvbiBvZiBDRDQgY2VsbHMuCgpUd28gQ0Q4IFBvcHVsYXRpb25zIGluIFBDMSB2cyBQQzIgQWZ0ZXIgTksgUmVtb3ZhbDoKUmVtb3ZpbmcgTksgY2VsbHMgZnJvbSB0aGUgcmVmZXJlbmNlIGRhdGFzZXQgaGFzIGhhZCBhbiBpbmZsdWVuY2Ugb24gdGhlIHBvc2l0aW9uaW5nIG9mIENEOCBUIGNlbGxzIGluIHRoZSBQQ0Egc3BhY2UuIFRoaXMgZWZmZWN0IGlzIHNlZW4gaW4gdGhlIGVtZXJnZW5jZSBvZiB0d28gQ0Q4IGNlbGwgcG9wdWxhdGlvbnMgaW4gdGhlIFBDMSB2cyBQQzIgcGxvdCwgaW5kaWNhdGluZyB0aGF0IHRoZSBwcmVzZW5jZSBvZiBOSyBjZWxscyB3YXMgYWZmZWN0aW5nIHRoZSBkaXN0cmlidXRpb24gb2YgQ0Q4IGNlbGxzLgoKRGlzdGluY3QgQ0Q0LCBDRDE0LCBhbmQgQ0Q4IFBvcHVsYXRpb25zIGluIFBDMSB2cyBQQzMgQWZ0ZXIgTksgUmVtb3ZhbDoKVGhlIHJlbW92YWwgb2YgTksgY2VsbHMgZnJvbSB0aGUgcmVmZXJlbmNlIGRhdGFzZXQgaGFzIGJyb3VnaHQgYWJvdXQgY2xlYXJlciBzZXBhcmF0aW9uIGJldHdlZW4gQ0Q0IFQgY2VsbHMsIENEMTQsIGFuZCBDRDggY2VsbHMgaW4gdGhlIFBDMSB2cyBQQzMgcGxvdC4gVGhlIG1hc2tpbmcgZWZmZWN0IG9mIE5LIGNlbGxzIG9uIHRoZSBkaXN0aW5jdGlvbiBiZXR3ZWVuIHRoZXNlIHBvcHVsYXRpb25zIGhhcyBiZWVuIGFsbGV2aWF0ZWQuCgpUd28gQ0Q4IFBvcHVsYXRpb25zIGluIFBDMiB2cyBQQzMgQWZ0ZXIgQ0Q0IFJlbW92YWw6ClRoZSBhYnNlbmNlIG9mIENENCBjZWxscyBpbiB0aGUgcmVmZXJlbmNlIGRhdGFzZXQgaGFzIGFsbG93ZWQgZm9yIHRoZSBpZGVudGlmaWNhdGlvbiBvZiBzdWJ0bGUgaGV0ZXJvZ2VuZWl0eSB3aXRoaW4gQ0Q4IGluIHRoZSBQQzIgdnMgUEMzIHBsb3QuIFRoaXMgZmluZGluZyB1bmRlcnNjb3JlcyBob3cgdGhlIHByZXNlbmNlIG9mIENENCBjZWxscyB3YXMgaW1wYWN0aW5nIHRoZSByZXByZXNlbnRhdGlvbiBvZiBDRDggY2VsbCB2YXJpYWJpbGl0eS4KCg==